├── .github ├── CODEOWNERS ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── pull-request.yml │ └── pypi-release.yml ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── README.md ├── examples ├── compliance_finding.py └── detection_finding.py ├── poetry.lock ├── py_ocsf_models ├── __init__.py ├── events │ ├── __init__.py │ ├── base_event.py │ └── findings │ │ ├── __init__.py │ │ ├── activity_id.py │ │ ├── application_security_posture_finding.py │ │ ├── application_security_posture_finding_type_id.py │ │ ├── category_uid.py │ │ ├── class_uid.py │ │ ├── compliance_finding.py │ │ ├── compliance_finding_type_id.py │ │ ├── confidence_id.py │ │ ├── detection_finding.py │ │ ├── detection_finding_type_id.py │ │ ├── disposition_id.py │ │ ├── finding.py │ │ ├── impact_id.py │ │ ├── risk_level_id.py │ │ ├── severity_id.py │ │ └── status_id.py └── objects │ ├── __init__.py │ ├── account.py │ ├── affected_software_package.py │ ├── analytic.py │ ├── api.py │ ├── assessment.py │ ├── check.py │ ├── cloud.py │ ├── compliance.py │ ├── compliance_status.py │ ├── container.py │ ├── cve.py │ ├── cvss.py │ ├── cwe.py │ ├── device.py │ ├── device_hardware_info.py │ ├── dns_query.py │ ├── enrichment.py │ ├── epss.py │ ├── evidence_artifacts.py │ ├── finding_info.py │ ├── fingerprint.py │ ├── geolocation.py │ ├── group.py │ ├── image.py │ ├── kb_article.py │ ├── kill_chain_phase.py │ ├── ldap_person.py │ ├── metadata.py │ ├── metric.py │ ├── mitre_attack.py │ ├── network_interface.py │ ├── observable.py │ ├── operating_system.py │ ├── organization.py │ ├── policy.py │ ├── product.py │ ├── related_event.py │ ├── remediation.py │ ├── request_elements.py │ ├── resource_details.py │ ├── response_elements.py │ ├── service.py │ ├── url.py │ ├── user.py │ ├── verdict.py │ └── vulnerability_details.py ├── pyproject.toml └── tests ├── application_security_posture_finding_test.py ├── compliance_finding_test.py └── detection_finding_test.py /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @prowler-cloud/sdk 2 | 3 | # To protect a repository fully against unauthorized changes, you also need to define an owner for the CODEOWNERS file itself. 4 | # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#codeowners-and-branch-protection 5 | /.github/ @prowler-cloud/sdk 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | target-branch: main 13 | labels: 14 | - "dependencies" 15 | - "pip" 16 | - package-ecosystem: "github-actions" 17 | directory: "/" 18 | schedule: 19 | interval: "monthly" 20 | target-branch: main 21 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Context 2 | 3 | Please include relevant motivation and context for this PR. 4 | 5 | 6 | ### Description 7 | 8 | Please include a summary of the change and which issue is fixed. List any dependencies that are required for this change. 9 | 10 | 11 | ### License 12 | 13 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. 14 | -------------------------------------------------------------------------------- /.github/workflows/pull-request.yml: -------------------------------------------------------------------------------- 1 | name: PR - Lint and Test 2 | 3 | permissions: 4 | contents: read 5 | pull-requests: write 6 | 7 | on: 8 | push: 9 | branches: 10 | - "main" 11 | pull_request: 12 | branches: 13 | - "main" 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | strategy: 19 | matrix: 20 | python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] 21 | 22 | steps: 23 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 24 | 25 | - name: Install poetry 26 | run: | 27 | python -m pip install --upgrade pip 28 | pipx install poetry 29 | 30 | - name: Set up Python ${{ matrix.python-version }} 31 | uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 32 | with: 33 | python-version: ${{ matrix.python-version }} 34 | cache: "poetry" 35 | 36 | - name: Install dependencies 37 | run: | 38 | poetry install 39 | poetry run pip list 40 | 41 | - name: Poetry check 42 | run: | 43 | poetry check --lock 44 | 45 | - name: Lint with flake8 46 | run: | 47 | poetry run flake8 . --ignore=E501,W503 48 | 49 | - name: Lint with ruff 50 | uses: astral-sh/ruff-action@eaf0ecdd668ceea36159ff9d91882c9795d89b49 # v3.4.0 51 | 52 | - name: Checking format with black 53 | run: | 54 | poetry run black --check . 55 | 56 | - name: Lint with pylint 57 | run: | 58 | poetry run pylint --disable=W,C,R,E -j 0 -rn -sn py_ocsf_models/ 59 | 60 | - name: Check types with mypy 61 | run: | 62 | poetry run mypy --strict py_ocsf_models/ 63 | 64 | - name: Bandit 65 | run: | 66 | poetry run bandit -q -lll -x './tests' -r . 67 | 68 | - name: Safety 69 | run: | 70 | poetry run safety check --ignore 70612 71 | 72 | - name: Vulture 73 | run: | 74 | poetry run vulture --min-confidence 100 . 75 | 76 | - name: Test with pytest 77 | run: | 78 | poetry run pytest -n auto --cov=./py_ocsf_models --cov-report=xml tests 79 | 80 | - name: Upload coverage reports to Codecov 81 | uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 82 | with: 83 | token: ${{ secrets.CODECOV_TOKEN }} 84 | slug: prowler-cloud/py-ocsf-models 85 | -------------------------------------------------------------------------------- /.github/workflows/pypi-release.yml: -------------------------------------------------------------------------------- 1 | name: PyPI release 2 | permissions: 3 | contents: read 4 | 5 | on: 6 | release: 7 | types: [published] 8 | 9 | env: 10 | RELEASE_TAG: ${{ github.event.release.tag_name }} 11 | PYTHON_VERSION: 3.11 12 | # CACHE: "poetry" 13 | 14 | jobs: 15 | release: 16 | runs-on: ubuntu-latest 17 | env: 18 | POETRY_VIRTUALENVS_CREATE: "false" 19 | 20 | name: Release py-ocsf-models to PyPI 21 | steps: 22 | 23 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 24 | 25 | - name: Install dependencies 26 | run: | 27 | pipx install poetry==2.1.1 28 | 29 | - name: Setup Python 30 | uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 31 | with: 32 | python-version: ${{ env.PYTHON_VERSION }} 33 | # cache: ${{ env.CACHE }} 34 | 35 | - name: Build package 36 | run: | 37 | poetry build 38 | 39 | - name: Publish package to PyPI 40 | run: | 41 | poetry config pypi-token.pypi ${{ secrets.PYPI_API_TOKEN }} 42 | poetry publish 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | 162 | # vscode 163 | .vscode/ 164 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | ## GENERAL 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v4.5.0 5 | hooks: 6 | - id: check-merge-conflict 7 | - id: check-yaml 8 | args: ["--unsafe"] 9 | - id: check-json 10 | - id: end-of-file-fixer 11 | - id: trailing-whitespace 12 | - id: no-commit-to-branch 13 | - id: pretty-format-json 14 | args: ["--autofix", --no-sort-keys, --no-ensure-ascii] 15 | 16 | ## TOML 17 | - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks 18 | rev: v2.12.0 19 | hooks: 20 | - id: pretty-format-toml 21 | args: [--autofix] 22 | files: pyproject.toml 23 | 24 | ## PYTHON 25 | - repo: https://github.com/myint/autoflake 26 | rev: v2.2.1 27 | hooks: 28 | - id: autoflake 29 | args: 30 | [ 31 | "--in-place", 32 | "--remove-all-unused-imports", 33 | "--remove-unused-variable", 34 | ] 35 | 36 | - repo: https://github.com/timothycrosley/isort 37 | rev: 5.13.2 38 | hooks: 39 | - id: isort 40 | args: ["--profile", "black"] 41 | 42 | - repo: https://github.com/psf/black 43 | rev: 24.1.1 44 | hooks: 45 | - id: black 46 | 47 | - repo: https://github.com/pycqa/flake8 48 | rev: 7.0.0 49 | hooks: 50 | - id: flake8 51 | exclude: contrib 52 | args: ["--ignore=E501,W503"] 53 | 54 | - repo: https://github.com/astral-sh/ruff-pre-commit 55 | rev: v0.3.2 56 | hooks: 57 | # Run the linter. 58 | - id: ruff 59 | args: [--fix] 60 | 61 | - repo: https://github.com/python-poetry/poetry 62 | rev: 2.1.1 63 | hooks: 64 | - id: poetry-check 65 | - id: poetry-lock 66 | 67 | - repo: local 68 | hooks: 69 | - id: pylint 70 | name: pylint 71 | entry: bash -c 'pylint --disable=W,C,R,E -j 0 -rn -sn py_ocsf_models/' 72 | language: system 73 | files: '.*\.py' 74 | 75 | - id: mypy 76 | name: mypy 77 | entry: bash -c 'mypy --strict ./py_ocsf_models' 78 | language: system 79 | files: '.*\.py' 80 | 81 | - id: trufflehog 82 | name: TruffleHog 83 | description: Detect secrets in your data. 84 | entry: bash -c 'trufflehog --no-update git file://. --only-verified --fail' 85 | # For running trufflehog in docker, use the following entry instead: 86 | # entry: bash -c 'docker run -v "$(pwd):/workdir" -i --rm trufflesecurity/trufflehog:latest git file:///workdir --only-verified --fail' 87 | language: system 88 | stages: ["pre-commit", "pre-push"] 89 | 90 | - id: bandit 91 | name: bandit 92 | description: "Bandit is a tool for finding common security issues in Python code" 93 | entry: bash -c 'bandit -q -lll -x '*_test.py,./contrib/' -r .' 94 | language: system 95 | files: '.*\.py' 96 | 97 | - id: safety 98 | name: safety 99 | description: "Safety is a tool that checks your installed dependencies for known security vulnerabilities" 100 | entry: bash -c 'safety check --ignore 70612' 101 | language: system 102 | 103 | - id: vulture 104 | name: vulture 105 | description: "Vulture finds unused code in Python programs." 106 | entry: bash -c 'vulture --exclude "contrib" --min-confidence 100 .' 107 | language: system 108 | files: '.*\.py' 109 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright @ 2024 Prowler, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # py-ocsf-models 2 | 3 | The `py-ocsf-models` package offers a Python implementation of the Open Cybersecurity Schema Framework (OCSF) models, facilitating the manipulation and understanding of cybersecurity data within Python applications. This package provides a rich set of models covering various aspects of cybersecurity events, findings, objects, and profiles as defined by the OCSF Schema, enabling developers to work with structured cybersecurity data efficiently. 4 | 5 | In [Prowler](https://github.com/prowler-cloud/prowler), we leverage the py-ocsf-models package to generate JSON formatted OCSF outputs, specifically focusing on Detection Findings. This integration facilitates the standardization and sharing of cybersecurity findings in a structured and widely-accepted format, enhancing the interoperability between different security tools and platforms. 6 | 7 | ## Features 8 | 9 | - **Comprehensive OCSF Schema Implementation**: Includes models for events, findings, objects, and profiles, covering the entire OCSF Schema. 10 | - **Easy Data Manipulation**: Easily create, modify, and interact with cybersecurity data structures. 11 | - **Serialization and Deserialization Support**: Convert OCSF model instances to and from JSON for easy storage and transmission. 12 | - **Extensible Design**: Extend and customize models to fit specific requirements while staying compliant with the OCSF schema. 13 | 14 | ## OCSF Coverage 15 | 16 | - Detection Finding 17 | - Compliance Finding 18 | - Application Security Posture Finding 19 | 20 | ## Installation 21 | 22 | Install `py-ocsf-models` using pip: 23 | 24 | ```bash 25 | pip install py-ocsf-models 26 | ``` 27 | 28 | Import the package in your Python application: 29 | 30 | ```python 31 | import py_ocsf_models 32 | ``` 33 | 34 | ## Usage Examples 35 | 36 | You can find ready-to-run examples demonstrating how to generate events using the OCSF schema in the [examples](./examples/) folder. 37 | 38 | ## How to Release 39 | 40 | To release a new version of `py-ocsf-models`: 41 | 42 | 1. **Create a PR with version update**: Update the version number in `pyproject.toml` and create a pull request with the changes. 43 | 44 | 2. **Create a GitHub release**: Once the PR is merged into the master branch, create a new release in GitHub from the master branch. This will automatically trigger the `pypi-release.yml` workflow to publish the package to PyPI. 45 | 46 | ## Contributing 47 | Contributions are welcome! Whether you're fixing a bug, adding new features, or improving the documentation, please feel free to make a pull request or open an issue. 48 | 49 | ## License 50 | This project is licensed under the Apache-2.0 License - see the [LICENSE](LICENSE) file for details. 51 | 52 | ## Acknowledgments 53 | This package is built to support and encourage the adoption of the Open Cybersecurity Schema Framework (OCSF) and facilitate the handling of cybersecurity data in Python applications. 54 | 55 | ## Support 56 | For support, questions, or feedback, please open an issue on the GitHub repository. 57 | -------------------------------------------------------------------------------- /examples/compliance_finding.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # The following is an example demonstrating how to create an 4 | # OCSF Compliance Finding using py-ocsf-models. 5 | # This example showcases the instantiation of various models and 6 | # their association to create a rich, structured representation of 7 | # a compliance finding. 8 | 9 | # Run me from the project root directory with: 10 | # `poetry run examples/compliance_finding.py | jq` 11 | 12 | from datetime import datetime 13 | 14 | from py_ocsf_models import OCSF_VERSION 15 | from py_ocsf_models.events.base_event import SeverityID 16 | from py_ocsf_models.events.findings.compliance_finding import ( 17 | ComplianceFinding, 18 | ComplianceFindingTypeID, 19 | ) 20 | from py_ocsf_models.events.findings.finding import ActivityID, CategoryUID, ClassUID 21 | from py_ocsf_models.objects.assessment import Assessment 22 | from py_ocsf_models.objects.check import Check 23 | from py_ocsf_models.objects.compliance import Compliance 24 | from py_ocsf_models.objects.compliance_status import StatusID as ComplianceStatusID 25 | from py_ocsf_models.objects.evidence_artifacts import EvidenceArtifacts 26 | from py_ocsf_models.objects.finding_info import FindingInformation 27 | from py_ocsf_models.objects.metadata import Metadata 28 | from py_ocsf_models.objects.product import Feature, Product 29 | from py_ocsf_models.objects.resource_details import ResourceDetails 30 | from py_ocsf_models.objects.url import URL 31 | from py_ocsf_models.objects.verdict import VerdictID 32 | 33 | compliance_finding = ComplianceFinding( 34 | activity_id=ActivityID.Create.value, 35 | category_uid=CategoryUID.Findings.value, 36 | class_uid=ClassUID.ComplianceFinding.value, 37 | metadata=Metadata( 38 | version=OCSF_VERSION, 39 | product=Product( 40 | feature=Feature(name="Name", uid="123", version="Version"), 41 | lang="en", 42 | name="Name", 43 | path="Path", 44 | cpe_name="CPE Name", 45 | url_string="https://www.example.com", 46 | uid="123", 47 | vendor_name="Vendor Name", 48 | version="Version", 49 | ), 50 | ), 51 | compliance=Compliance( 52 | assessments=[ 53 | Assessment( 54 | category="Access Control", 55 | name="github authn configuration", 56 | desc=( 57 | "This assessment checks that the repository being " 58 | "assessed is hosted on GitHub" 59 | ), 60 | uid="123", 61 | meets_criteria=True, 62 | ) 63 | ], 64 | category="Supply Chain Risk Assessment", 65 | checks=[ 66 | Check( 67 | name=( 68 | "OSPS-AC-01.01: When a user attempts to access a sensitive " 69 | "resource in the project's version control system, the " 70 | "system MUST require the user to complete a multi-factor " 71 | "authentication process." 72 | ), 73 | uid="OSPS-AC-01.01", 74 | version="2025-02-25", 75 | severity_id=SeverityID.Critical.value, 76 | standards=["Open Source Project Security Baseline v2025-02-25"], 77 | status="Pass", 78 | status_id=ComplianceStatusID.Pass.value, 79 | ) 80 | ], 81 | control="OSPS-AC-01", 82 | desc=( 83 | "Enforce multi-factor authentication for the project's " 84 | "version control system, requiring collaborators to provide " 85 | "a second form of authentication when accessing sensitive " 86 | "data or modifying repository settings. Passkeys are " 87 | "acceptable for this control." 88 | ), 89 | requirements=["https://baseline.openssf.org/versions/2025-02-25#osps-ac-0101"], 90 | standards=["Open Source Project Security Baseline v2025-02-25"], 91 | status_id=ComplianceStatusID.Pass.value, 92 | ), 93 | evidences=[ 94 | EvidenceArtifacts( 95 | name="GitHub required and default configuration", 96 | resources=[ 97 | ResourceDetails( 98 | name="security-baseline", 99 | namespace="ossf", 100 | uid="https://github.com/ossf/security-baseline", 101 | type="GitHub", 102 | criticality="Critical", 103 | hostname="https://github.com/ossf/security-baseline", 104 | ) 105 | ], 106 | url=URL( 107 | url_string="https://github.com/ossf/security-baseline", 108 | ), 109 | verdict_id=VerdictID.Benign.value, 110 | ) 111 | ], 112 | finding_info=FindingInformation( 113 | title=( 114 | "Repository is hosted on GitHub and subject to required and " 115 | "default configured MFA authentication" 116 | ), 117 | desc=( 118 | "The repository is verified as hosted on GitHub and adheres " 119 | "to GitHub's authentication policies for MFA. See " 120 | "https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/about-mandatory-two-factor-authentication" 121 | ), 122 | uid="123", 123 | ), 124 | severity_id=SeverityID.Critical.value, 125 | time=int(datetime.now().timestamp()), 126 | timezone_offset=0, 127 | type_uid=ComplianceFindingTypeID.Create, 128 | ) 129 | 130 | # Serialize to JSON 131 | compliance_finding_json = compliance_finding.json(exclude_unset=True) 132 | print(compliance_finding_json) 133 | -------------------------------------------------------------------------------- /examples/detection_finding.py: -------------------------------------------------------------------------------- 1 | # The following is an example demonstrating how to create a full OCSF Detection Finding using py-ocsf-models. 2 | # This example showcases the instantiation of various models and their association to create a rich, 3 | # structured representation of a detection finding. 4 | 5 | import uuid 6 | from datetime import datetime 7 | 8 | from py_ocsf_models.events.findings.detection_finding import DetectionFinding 9 | from py_ocsf_models.events.findings.finding import FindingInformation 10 | from py_ocsf_models.objects.api import ( 11 | API, 12 | Group, 13 | RequestElements, 14 | ResponseElements, 15 | Service, 16 | ) 17 | from py_ocsf_models.objects.cloud import Account, Cloud, Organization 18 | from py_ocsf_models.objects.container import Container, FingerPrint, Image 19 | from py_ocsf_models.objects.dns_query import DNSOpcodeID, DNSQuery 20 | from py_ocsf_models.objects.evidence_artifacts import EvidenceArtifacts 21 | from py_ocsf_models.objects.metadata import Metadata 22 | from py_ocsf_models.objects.operating_system import OperatingSystem 23 | from py_ocsf_models.objects.product import Feature, Product 24 | from py_ocsf_models.objects.remediation import KBArticle, Remediation 25 | from py_ocsf_models.objects.resource_details import ResourceDetails 26 | from py_ocsf_models.objects.vulnerability_details import VulnerabilityDetails 27 | 28 | # Example instantiation of a DetectionFinding object with nested structures 29 | detection_finding = DetectionFinding( 30 | metadata=Metadata( 31 | version="1.0", 32 | product=Product( 33 | feature=Feature(name="Name", uid="123", version="Version"), 34 | lang="en", 35 | name="Name", 36 | path="Path", 37 | cpe_name="CPE Name", 38 | url_string="https://www.example.com", 39 | uid="123", 40 | vendor_name="Vendor Name", 41 | version="Version", 42 | ), 43 | ), 44 | finding_info=FindingInformation( 45 | title="Title", 46 | uid="123", 47 | ), 48 | severity_id=1, 49 | activity_name="Activity Name", 50 | activity_id=1, 51 | comment="Comment", 52 | confidence="Low", 53 | confidence_id=1, 54 | confidence_score=123, 55 | end_time=datetime.now(), 56 | start_time=datetime.now(), 57 | resources=[ 58 | ResourceDetails( 59 | id="123", 60 | name="Resource 1", 61 | type="Resource", 62 | details="Details of the resource", 63 | ) 64 | ], 65 | category_name="Findings", 66 | category_uid=2, 67 | class_name="Detection Finding", 68 | class_uid=2004, 69 | api=API( 70 | request=RequestElements( 71 | containers=[ 72 | Container( 73 | hash=FingerPrint( 74 | algorithm="SHA256", 75 | algorithm_id=3, 76 | value="123", 77 | ), 78 | image=Image( 79 | tag="Tag 1", 80 | name="Image 1", 81 | labels=["Label 1"], 82 | path="Path 1", 83 | uid="123", 84 | ), 85 | tag="Tag 1", 86 | name="Container 1", 87 | network_driver="Network Driver 1", 88 | orchestrator="Orchestrator 1", 89 | pod_uuid=str(uuid.uuid4()), 90 | runtime="Runtime 1", 91 | size=123, 92 | uid="123", 93 | ) 94 | ], 95 | data={"key": "value"}, 96 | flags=["Flag 1"], 97 | uid="123", 98 | ), 99 | response=ResponseElements( 100 | containers=[ 101 | Container( 102 | hash=FingerPrint( 103 | algorithm="SHA256", 104 | algorithm_id=3, 105 | value="123", 106 | ), 107 | image=Image( 108 | tag="Tag 1", 109 | name="Image 1", 110 | labels=["Label 1"], 111 | path="Path 1", 112 | uid="123", 113 | ), 114 | tag="Tag 1", 115 | name="Container 1", 116 | network_driver="Network Driver 1", 117 | orchestrator="Orchestrator 1", 118 | pod_uuid=str(uuid.uuid4()), 119 | runtime="Runtime 1", 120 | size=123, 121 | uid="123", 122 | ) 123 | ], 124 | data={"key": "value"}, 125 | error="Error", 126 | error_message="Error Message", 127 | flags=["Flag 1"], 128 | message="Message", 129 | code=123, 130 | ), 131 | group=Group( 132 | type="Group", 133 | desc="Details of the group", 134 | domain="Domain 1", 135 | name="Group 1", 136 | privileges=["Privilege 1"], 137 | uid="123", 138 | ), 139 | operation="GET", 140 | service=Service( 141 | labels=["Label 1"], 142 | name="Service 1", 143 | uid="123", 144 | version="1.0", 145 | ), 146 | version="1.0", 147 | ), 148 | cloud=Cloud( 149 | account=Account( 150 | name="Account 1", type="Account", type_id="3", uid="123", labels=["Label 1"] 151 | ), 152 | zone="Zone 1", 153 | org=Organization( 154 | name="Organization 1", ou_uid="123", ou_name="OU 1", uid="123" 155 | ), 156 | project_uid="123", 157 | provider="Provider 1", 158 | region="Region 1", 159 | ), 160 | container=Container( 161 | hash=FingerPrint( 162 | algorithm="SHA256", 163 | algorithm_id=3, 164 | value="123", 165 | ), 166 | image=Image( 167 | tag="Tag 1", 168 | name="Image 1", 169 | labels=["Label 1"], 170 | path="Path 1", 171 | uid="123", 172 | ), 173 | tag="Tag 1", 174 | name="Container 1", 175 | network_driver="Network Driver 1", 176 | orchestrator="Orchestrator 1", 177 | pod_uuid=str(uuid.uuid4()), 178 | runtime="Runtime 1", 179 | size=123, 180 | uid="123", 181 | ), 182 | count=123, 183 | duration=123, 184 | time=datetime.now(), 185 | evidences=[ 186 | EvidenceArtifacts( 187 | api=API( 188 | request=RequestElements( 189 | containers=[ 190 | Container( 191 | hash=FingerPrint( 192 | algorithm="SHA256", 193 | algorithm_id=3, 194 | value="123", 195 | ), 196 | image=Image( 197 | tag="Tag 1", 198 | name="Image 1", 199 | labels=["Label 1"], 200 | path="Path 1", 201 | uid="123", 202 | ), 203 | tag="Tag 1", 204 | name="Container 1", 205 | network_driver="Network Driver 1", 206 | orchestrator="Orchestrator 1", 207 | pod_uuid=str(uuid.uuid4()), 208 | runtime="Runtime 1", 209 | size=123, 210 | uid="123", 211 | ) 212 | ], 213 | data={"key": "value"}, 214 | flags=["Flag 1"], 215 | uid="123", 216 | ), 217 | response=ResponseElements( 218 | containers=[ 219 | Container( 220 | hash=FingerPrint( 221 | algorithm="SHA256", 222 | algorithm_id=3, 223 | value="123", 224 | ), 225 | image=Image( 226 | tag="Tag 1", 227 | name="Image 1", 228 | labels=["Label 1"], 229 | path="Path 1", 230 | uid="123", 231 | ), 232 | tag="Tag 1", 233 | name="Container 1", 234 | network_driver="Network Driver 1", 235 | orchestrator="Orchestrator 1", 236 | pod_uuid=str(uuid.uuid4()), 237 | runtime="Runtime 1", 238 | size=123, 239 | uid="123", 240 | ) 241 | ], 242 | data={"key": "value"}, 243 | error="Error", 244 | error_message="Error Message", 245 | flags=["Flag 1"], 246 | message="Message", 247 | code=123, 248 | ), 249 | group=Group( 250 | type="Group", 251 | desc="Details of the group", 252 | domain="Domain 1", 253 | name="Group 1", 254 | privileges=["Privilege 1"], 255 | uid="123", 256 | ), 257 | operation="GET", 258 | service=Service( 259 | labels=["Label 1"], 260 | name="Service 1", 261 | uid="123", 262 | version="1.0", 263 | ), 264 | version="1.0", 265 | ), 266 | query=DNSQuery( 267 | opcode="Query", 268 | opcode_id=DNSOpcodeID.Query, 269 | hostname="www.example.com", 270 | packet_uid=123, 271 | class_="IN", 272 | type="A", 273 | ), 274 | data={"key": "value"}, 275 | ) 276 | ], 277 | impact="Impact", 278 | impact_score=123, 279 | impact_id=123, 280 | remediation=Remediation( 281 | desc="Description", 282 | kb_article_list=[ 283 | KBArticle( 284 | classification="Classification", 285 | created_time=datetime.now(), 286 | os=OperatingSystem( 287 | cpu_bits=64, 288 | country="US", 289 | lang="en", 290 | name="Name", 291 | build="Build", 292 | edition="Edition", 293 | sp_name="SP Name", 294 | sp_ver=123, 295 | cpe_name="CPE Name", 296 | type="Type", 297 | type_id=100, 298 | version="Version", 299 | ), 300 | bulletin="Bulletin", 301 | product=Product( 302 | feature=Feature(name="Name", uid="123", version="Version"), 303 | lang="en", 304 | name="Name", 305 | path="Path", 306 | cpe_name="CPE Name", 307 | url_string="https://www.example.com", 308 | uid="123", 309 | vendor_name="Vendor Name", 310 | version="Version", 311 | ), 312 | severity="Severity", 313 | size=123, 314 | src_url="https://www.example.com", 315 | is_superseded=True, 316 | title="Title", 317 | uid="123", 318 | ) 319 | ], 320 | references=["https://www.example.com"], 321 | ), 322 | risk_level="Risk Level", 323 | risk_level_id=123, 324 | risk_score=123, 325 | risk_details="Risk Details", 326 | timezone_offset=123, 327 | type_id=123, 328 | type_name="Type Name", 329 | vulnerabilities=[ 330 | VulnerabilityDetails( 331 | desc="Description", 332 | is_exploit_available=True, 333 | first_seen_time=datetime.now(), 334 | kb_article_list=[ 335 | KBArticle( 336 | classification="Classification", 337 | created_time=datetime.now(), 338 | os=OperatingSystem( 339 | cpu_bits=64, 340 | country="US", 341 | lang="en", 342 | name="Name", 343 | build="Build", 344 | edition="Edition", 345 | sp_name="SP Name", 346 | sp_ver=123, 347 | cpe_name="CPE Name", 348 | type="Type", 349 | type_id=100, 350 | version="Version", 351 | ), 352 | bulletin="Bulletin", 353 | product=Product( 354 | feature=Feature(name="Name", uid="123", version="Version"), 355 | lang="en", 356 | name="Name", 357 | path="Path", 358 | cpe_name="CPE Name", 359 | url_string="https://www.example.com", 360 | uid="123", 361 | vendor_name="Vendor Name", 362 | version="Version", 363 | ), 364 | severity="Severity", 365 | size=123, 366 | src_url="https://www.example.com", 367 | is_superseded=True, 368 | title="Title", 369 | uid="123", 370 | ) 371 | ], 372 | last_seen_time=datetime.now(), 373 | references=["https://www.example.com"], 374 | related_vulnerabilities=["123"], 375 | remediation=Remediation( 376 | desc="Description", 377 | kb_article_list=[ 378 | KBArticle( 379 | classification="Classification", 380 | created_time=datetime.now(), 381 | os=OperatingSystem( 382 | cpu_bits=64, 383 | country="US", 384 | lang="en", 385 | name="Name", 386 | build="Build", 387 | edition="Edition", 388 | sp_name="SP Name", 389 | sp_ver=123, 390 | cpe_name="CPE Name", 391 | type="Type", 392 | type_id=100, 393 | version="Version", 394 | ), 395 | bulletin="Bulletin", 396 | product=Product( 397 | feature=Feature(name="Name", uid="123", version="Version"), 398 | lang="en", 399 | name="Name", 400 | path="Path", 401 | cpe_name="CPE Name", 402 | url_string="https://www.example.com", 403 | uid="123", 404 | vendor_name="Vendor Name", 405 | version="Version", 406 | ), 407 | severity="Severity", 408 | size=123, 409 | src_url="https://www.example.com", 410 | is_superseded=True, 411 | title="Title", 412 | uid="123", 413 | ) 414 | ], 415 | references=["https://www.example.com"], 416 | ), 417 | severity="Severity", 418 | title="Title", 419 | vendor_name="Vendor Name", 420 | ) 421 | ], 422 | ) 423 | 424 | # Serialize to JSON 425 | detection_finding_json = detection_finding.json() 426 | print(detection_finding_json) 427 | -------------------------------------------------------------------------------- /py_ocsf_models/__init__.py: -------------------------------------------------------------------------------- 1 | OCSF_VERSION = "1.5.0" 2 | -------------------------------------------------------------------------------- /py_ocsf_models/events/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prowler-cloud/py-ocsf-models/96e5bb0d29f1daa37ffec6e2339777d481211951/py_ocsf_models/events/__init__.py -------------------------------------------------------------------------------- /py_ocsf_models/events/base_event.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.events.findings.severity_id import SeverityID 6 | from py_ocsf_models.events.findings.status_id import StatusID 7 | from py_ocsf_models.objects.enrichment import Enrichment 8 | from py_ocsf_models.objects.metadata import Metadata 9 | from py_ocsf_models.objects.observable import Observable 10 | 11 | 12 | class BaseEvent(BaseModel): 13 | """ 14 | The base event is a generic and concrete event. It also defines a set of attributes available in most event classes. As a generic event that does not belong to any event category, it could be used to log events that are not otherwise defined by the schema. 15 | 16 | Attributes: 17 | - Enrichments (enrichments) [Optional]: Additional information from external sources associated with the finding. 18 | - Message (message) [Optional]: Description of the event/finding as defined by the source. 19 | - Metadata (metadata) [Required]: Data providing context for the event/finding. 20 | - Observables (observables) [Optional]: Observable elements associated with the event/finding. 21 | - Raw Data (raw_data) [Optional]: Original data as received from the source. 22 | - Severity (severity) [Optional]: The event/finding severity, normalized to the caption of the severity_id value. In the case of 'Other', it is defined by the source. 23 | - Severity ID (severity_id) [Required]: The level of severity assigned to the event/finding. 24 | - Status (status) [Optional]: The normalized status of the Finding set by the consumer normalized to the caption of the status_id value. In the case of 'Other', it is defined by the source. 25 | - Status Code (status_code) [Optional]: The event status code, as reported by the event source. For example, in a Windows Failed Authentication event, this would be the value of 'Failure Code', e.g. 0x18. 26 | - Status Details (status_detail) [Optional]: The status details contains additional information about the event/finding outcome. 27 | - Status ID (status_id) [Optional]: The normalized status identifier of the Finding, set by the consumer. 28 | - Unmapped Data (unmapped) [Optional]: The attributes that are not mapped to the event schema. The names and values of those attributes are specific to the event source. 29 | """ 30 | 31 | enrichments: Optional[list[Enrichment]] 32 | message: Optional[str] 33 | metadata: Metadata 34 | observables: Optional[list[Observable]] 35 | raw_data: Optional[str] 36 | severity_id: SeverityID 37 | severity: Optional[str] 38 | status: Optional[str] 39 | status_code: Optional[str] 40 | status_detail: Optional[str] 41 | status_id: Optional[StatusID] 42 | unmapped: Optional[object] 43 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prowler-cloud/py-ocsf-models/96e5bb0d29f1daa37ffec6e2339777d481211951/py_ocsf_models/events/findings/__init__.py -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/activity_id.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class ActivityID(IntEnum): 5 | """ 6 | The normalized identifier of the finding activity. 7 | 8 | 0 Unknown: The event activity is unknown. 9 | 1 Create: A finding was created. 10 | 2 Update: A finding was updated. 11 | 3 Close: A finding was closed. 12 | 99 Other: The event activity is not mapped. See the activity_name attribute, which contains a data source specific value. 13 | """ 14 | 15 | Unknown = 0 16 | Create = 1 17 | Update = 2 18 | Close = 3 19 | Other = 99 20 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/application_security_posture_finding.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | from py_ocsf_models.events.findings.application_security_posture_finding_type_id import ( 7 | ApplicationSecurityPostureFindingTypeID, 8 | ) 9 | from py_ocsf_models.events.findings.category_uid import CategoryUID 10 | from py_ocsf_models.events.findings.class_uid import ClassUID 11 | from py_ocsf_models.events.findings.finding import Finding 12 | from py_ocsf_models.objects.device import Device 13 | from py_ocsf_models.objects.evidence_artifacts import EvidenceArtifacts 14 | from py_ocsf_models.objects.finding_info import FindingInformation 15 | from py_ocsf_models.objects.remediation import Remediation 16 | from py_ocsf_models.objects.resource_details import ResourceDetails 17 | from py_ocsf_models.objects.vulnerability_details import VulnerabilityDetails 18 | 19 | 20 | class ApplicationSecurityPostureFinding(Finding, BaseModel): 21 | """ 22 | The Application Security Posture Finding event is a notification about any bug, defect, deficiency, exploit, vulnerability, weakness or any other issue with software and related systems. Application Security Posture Findings typically involve reporting on the greater context including compliance, impacted resources, remediation guidance, specific code defects, and/or vulnerability metadata. Application Security Posture Findings can be reported by Threat & Vulnerability Management (TVM) tools, Application Security Posture Management (ASPM) tools, or other similar tools. Note: if the event producer is a security control, the security_control profile should be applied and its attacks information, if present, should be duplicated into the finding_info object. 23 | 24 | Attributes: 25 | Category (category_name): The event category name, as defined by CategoryUID.Findings.value. 26 | Class (class_name) [Optional]: The event class name, as defined by ClassUID.ApplicationSecurityPostureFinding.value. 27 | Class ID (class_uid): The unique identifier of a class. A Class describes the attributes available in an event. 28 | Device (device) [Optional]: The device object. 29 | Finding Information (finding_info): Describes metadata related to a security finding generated by a security tool or system. 30 | Remediation Guidance (remediation) [Optional]: Suggested steps to address the finding. 31 | Resources (resources) [Optional]: Describes details about resources that were the target of the activity that triggered the finding. 32 | Time (time) [Required]: The standardized time when the event occurred or the finding was created. 33 | Timezone Offset (timezone_offset) [Optional]: Difference in minutes from UTC. 34 | Type ID (type_uid): The event/finding type ID. It identifies the event's semantics and structure. The value is calculated by the logging system as: class_uid * 100 + activity_id. 35 | Type Name (type_name) [Optional]: The event/finding type name, as defined by the type_uid. 36 | Vulnerabilities (vulnerabilities) [Optional]: Vulnerabilities identified in the finding. 37 | """ 38 | 39 | category_name: str = CategoryUID.Findings.name 40 | category_uid = CategoryUID.Findings.value 41 | class_name: Optional[str] = ClassUID.ApplicationSecurityPostureFinding.name 42 | class_uid = ClassUID.ApplicationSecurityPostureFinding 43 | device: Optional[Device] 44 | evidences: Optional[list[EvidenceArtifacts]] 45 | finding_info: FindingInformation 46 | remediation: Optional[Remediation] 47 | resources: Optional[list[ResourceDetails]] 48 | time: int 49 | time_dt: Optional[datetime] 50 | timezone_offset: Optional[int] 51 | type_uid: ApplicationSecurityPostureFindingTypeID 52 | type_name: Optional[str] 53 | vulnerabilities: Optional[list[VulnerabilityDetails]] 54 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/application_security_posture_finding_type_id.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class ApplicationSecurityPostureFindingTypeID(IntEnum): 5 | """ 6 | The event/finding type ID. It identifies the event's semantics and structure. The value is calculated by the logging system as: class_uid * 100 + activity_id. 7 | 8 | """ 9 | 10 | Unknown = 200700 11 | Create = 200701 12 | Update = 200702 13 | Close = 200703 14 | Other = 200799 15 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/category_uid.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class CategoryUID(IntEnum): 5 | """ 6 | The category unique identifier of the event. 7 | 8 | 2 Findings: Findings events report findings, detections, and possible resolutions of malware, anomalies, or other actions performed by security products. 9 | """ 10 | 11 | Findings = 2 12 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/class_uid.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class ClassUID(IntEnum): 5 | """ 6 | The unique identifier of a class. A Class describes the attributes available in an event. 7 | 8 | 2003 ComplianceFinding: Compliance Finding events describe results of evaluations performed against resources, to check compliance with various Industry Frameworks or Security Standards such as NIST SP 800-53, CIS AWS Foundations Benchmark v1.4.0, ISO/IEC 27001 etc. Note: if the event producer is a security control, the security_control profile should be applied and its attacks information, if present, should be duplicated into the finding_info object. 9 | Note: If the Finding is an incident, i.e. requires incident workflow, also apply the incident profile or aggregate this finding into an Incident Finding. 10 | """ 11 | 12 | ComplianceFinding = 2003 13 | 14 | """ 15 | The unique identifier of a class. A Class describes the attributes available in an event. 16 | 17 | 2004 DetectionFinding: A Detection Finding describes detections or alerts generated by security products using correlation engines, detection engines or other methodologies. Note: if the product is a security control, the security_control profile should be applied and its attacks information should be duplicated into the finding_info object. Note: If the Finding is an incident, i.e. requires incident workflow, also apply the incident profile or aggregate this finding into an Incident Finding. 18 | """ 19 | DetectionFinding = 2004 20 | 21 | """ 22 | The unique identifier of a class. A Class describes the attributes available in an event. 23 | 24 | 2007 ApplicationSecurityPostureFinding: The Application Security Posture Finding event is a notification about any bug, defect, deficiency, exploit, vulnerability, weakness or any other issue with software and related systems 25 | """ 26 | ApplicationSecurityPostureFinding = 2007 27 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/compliance_finding.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | from py_ocsf_models.events.findings.category_uid import CategoryUID 7 | from py_ocsf_models.events.findings.class_uid import ClassUID 8 | from py_ocsf_models.events.findings.compliance_finding_type_id import ( 9 | ComplianceFindingTypeID, 10 | ) 11 | from py_ocsf_models.events.findings.finding import Finding 12 | from py_ocsf_models.objects.compliance import Compliance 13 | from py_ocsf_models.objects.device import Device 14 | from py_ocsf_models.objects.evidence_artifacts import EvidenceArtifacts 15 | from py_ocsf_models.objects.finding_info import FindingInformation 16 | from py_ocsf_models.objects.remediation import Remediation 17 | from py_ocsf_models.objects.resource_details import ResourceDetails 18 | 19 | 20 | class ComplianceFinding(Finding, BaseModel): 21 | """ 22 | A Compliance Finding describe results of evaluations performed against resources, to check compliance with various Industry Frameworks or Security Standards such as NIST SP 800-53, CIS AWS Foundations Benchmark v1.4.0, ISO/IEC 27001 etc. Note: if the event producer is a security control, the security_control profile should be applied and its attacks information, if present, should be duplicated into the finding_info object. Note: If the Finding is an incident, i.e. requires incident workflow, also apply the incident profile or aggregate this finding into an Incident Finding. 23 | 24 | Attributes: 25 | Category (category_name): The event category name, as defined by CategoryUID.Findings.value. 26 | Class (class_name) [Optional]: The event class name, as defined by ClassUID.ComplianceFinding.value. 27 | Class ID (class_uid): The unique identifier of a class. A Class describes the attributes available in an event. 28 | Compliance (compliance): The compliance object. 29 | Device (device) [Optional]: The device object. 30 | Evidences (evidences) [Optional]: Artifacts related to the security detection activities. 31 | Finding Information (finding_info): Describes metadata related to a security finding generated by a security tool or system. 32 | Remediation Guidance (remediation) [Optional]: Suggested steps to address the finding. 33 | Resources (resources) [Optional]: Describes details about resources that were the target of the activity that triggered the finding. 34 | Time (time) [Required]: The standardized time when the event occurred or the finding was created. 35 | Timezone Offset (timezone_offset) [Optional]: Difference in minutes from UTC. 36 | Type ID (type_uid): The event/finding type ID. It identifies the event's semantics and structure. The value is calculated by the logging system as: class_uid * 100 + activity_id. 37 | Type Name (type_name) [Optional]: The event/finding type name, as defined by the type_uid. 38 | """ 39 | 40 | category_name: str = CategoryUID.Findings.name 41 | category_uid = CategoryUID.Findings.value 42 | class_name: Optional[str] = ClassUID.ComplianceFinding.name 43 | class_uid = ClassUID.ComplianceFinding 44 | compliance: Compliance 45 | device: Optional[Device] 46 | evidences: Optional[list[EvidenceArtifacts]] 47 | finding_info: FindingInformation 48 | remediation: Optional[Remediation] 49 | resources: Optional[list[ResourceDetails]] 50 | time: int 51 | time_dt: Optional[datetime] 52 | timezone_offset: Optional[int] 53 | type_uid: ComplianceFindingTypeID 54 | type_name: Optional[str] 55 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/compliance_finding_type_id.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class ComplianceFindingTypeID(IntEnum): 5 | """ 6 | The event/finding type ID. It identifies the event's semantics and structure. The value is calculated by the logging system as: class_uid * 100 + activity_id. 7 | 8 | """ 9 | 10 | Unknown = 200300 11 | Create = 200301 12 | Update = 200302 13 | Close = 200303 14 | Other = 200399 15 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/confidence_id.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class ConfidenceID(IntEnum): 5 | """ 6 | The normalized confidence refers to the accuracy of the rule that created the finding. A rule with a low confidence means that the finding scope is wide and may create finding reports that may not be malicious in nature. 7 | 8 | 0 Unknown: The normalized confidence is unknown. 9 | 1 Low 10 | 2 Medium 11 | 3 High 12 | 99 Other: The confidence is not mapped to the defined enum values. See the confidence attribute, which contains a data source specific value. 13 | 14 | """ 15 | 16 | Unknown = 0 17 | Low = 1 18 | Medium = 2 19 | High = 3 20 | Other = 99 21 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/detection_finding.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | from py_ocsf_models.events.findings.category_uid import CategoryUID 7 | from py_ocsf_models.events.findings.class_uid import ClassUID 8 | from py_ocsf_models.events.findings.detection_finding_type_id import ( 9 | DetectionFindingTypeID, 10 | ) 11 | from py_ocsf_models.events.findings.finding import Finding 12 | from py_ocsf_models.events.findings.impact_id import ImpactID 13 | from py_ocsf_models.events.findings.risk_level_id import RiskLevelID 14 | from py_ocsf_models.events.findings.status_id import StatusID 15 | from py_ocsf_models.objects.api import API 16 | from py_ocsf_models.objects.cloud import Cloud 17 | from py_ocsf_models.objects.evidence_artifacts import EvidenceArtifacts 18 | from py_ocsf_models.objects.remediation import Remediation 19 | from py_ocsf_models.objects.resource_details import ResourceDetails 20 | from py_ocsf_models.objects.vulnerability_details import VulnerabilityDetails 21 | 22 | 23 | class DetectionFinding(Finding, BaseModel): 24 | """ 25 | A Detection Finding describes detections or alerts generated by security products using correlation engines, detection engines or other methodologies. Note: if the product is a security control, the security_control profile should be applied and its attacks information should be duplicated into the finding_info object. 26 | 27 | Attributes: 28 | - Affected Resources (resources) [Recommended]: Describes details about resources that were the target of the activity that triggered the finding. 29 | - Category (category_name): The event category name, as defined by category_uid value: Findings. 30 | - Class (class_name) [Optional]: The event class name, as defined by class_uid value: Detection Finding. 31 | - Class ID (class_uid): The unique identifier of a class. A Class describes the attributes available in an event. 32 | - Cloud (cloud) [Optional]: Describes details about the Cloud environment where the event was originally created or logged. 33 | - Count (count) [Optional]: Number of times similar events occurred within a specified timeframe. 34 | - Duration (duration) [Optional]: Time span of the event, from start to end, in milliseconds. 35 | - Event Time (time) [Required]: The standardized time when the event occurred or the finding was created. 36 | - Event Time (time_dt) [Optional]: The standardized time when the event occurred or the finding was created, in datetime format. 37 | - Evidence Artifacts (evidences) [Optional]: Artifacts related to the security detection activities. 38 | - Impact (impact) [Optional]: The impact, normalized to the caption of the impact_id value. In the case of 'Other', it is defined by the event source. 39 | - Impact Score (impact_score) [Optional]: The impact of the finding, valid range 0-100. 40 | - Impact ID (impact_id) [Optional]: The normalized impact of the finding. 41 | - Remediation Guidance (remediation) [Optional]: Suggested steps to address the finding. 42 | - Risk Level (risk_level) [Optional]: The risk level, normalized to the caption of the risk_level_id value. In the case of 'Other', it is defined by the event source. 43 | - Risk Level ID (risk_level_id) [Optional]: The normalized risk level id. 44 | - Risk Score (risk_score) [Optional]: The risk score as reported by the event source. 45 | - Risk Details (risk_details) [Optional]: Additional details about the risk. 46 | - Status ID (status_id) [Optional]: The normalized identifier of the event/finding severity. 47 | - Timezone Offset (timezone_offset) [Optional]: Difference in minutes from UTC. 48 | - Type ID (type_uid): The event/finding type ID. It identifies the event's semantics and structure. The value is calculated by the logging system as: class_uid * 100 + activity_id. 49 | - Type Name (type_name) [Optional]: The event/finding type name, as defined by the type_uid. 50 | - Vulnerabilities (vulnerabilities) [Optional]: Vulnerabilities identified in the finding. 51 | 52 | If the Cloud profile is needed: 53 | - API Details (api) [Optional]: Describes details about a typical API (Application Programming Interface) call. 54 | - Cloud (cloud): Describes details about the Cloud environment where the event was originally created or logged 55 | """ 56 | 57 | resources: Optional[list[ResourceDetails]] 58 | category_name: str = CategoryUID.Findings.name 59 | category_uid = CategoryUID.Findings.value 60 | class_name: Optional[str] = "Detection Finding" 61 | class_uid = ClassUID.DetectionFinding 62 | cloud: Optional[Cloud] 63 | api: Optional[API] 64 | count: Optional[int] 65 | duration: Optional[int] 66 | evidences: Optional[list[EvidenceArtifacts]] 67 | impact: Optional[str] 68 | impact_score: Optional[int] 69 | impact_id: Optional[ImpactID] 70 | remediation: Optional[Remediation] 71 | risk_level: Optional[str] 72 | risk_level_id: Optional[RiskLevelID] 73 | risk_score: Optional[int] 74 | risk_details: Optional[str] 75 | status_id: Optional[StatusID] 76 | time: int 77 | time_dt: Optional[datetime] 78 | timezone_offset: Optional[int] 79 | type_uid: DetectionFindingTypeID 80 | type_name: Optional[str] 81 | vulnerabilities: Optional[list[VulnerabilityDetails]] 82 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/detection_finding_type_id.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class DetectionFindingTypeID(IntEnum): 5 | """ 6 | The event/finding type ID. It identifies the event's semantics and structure. The value is calculated by the logging system as: class_uid * 100 + activity_id. 7 | 8 | """ 9 | 10 | Unknown = 200400 11 | Create = 200401 12 | Update = 200402 13 | Close = 200403 14 | Other = 200499 15 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/disposition_id.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class DispositionID(IntEnum): 5 | """ 6 | Describes the outcome or action taken by a security control, such as access control checks, malware detections or various types of policy violations. 7 | 8 | 0 Unknown The disposition is unknown. 9 | 1 Allowed Granted access or allowed the action to the protected resource. 10 | 2 Blocked Denied access or blocked the action to the protected resource. 11 | 3 Quarantined A suspicious file or other content was moved to a benign location. 12 | 4 Isolated A session was isolated on the network or within a browser. 13 | 5 Deleted A file or other content was deleted. 14 | 6 Dropped The request was detected as a threat and resulted in the connection being dropped. 15 | 7 Custom Action A custom action was executed such as running of a command script. Use the message attribute of the base class for details. 16 | 8 Approved A request or submission was approved. For example, when a form was properly filled out and submitted. This is distinct from 1 'Allowed'. 17 | 9 Restored A quarantined file or other content was restored to its original location. 18 | 10 Exonerated A suspicious or risky entity was deemed to no longer be suspicious (re-scored). 19 | 11 Corrected A corrupt file or configuration was corrected. 20 | 12 Partially Corrected A corrupt file or configuration was partially corrected. 21 | 13 Uncorrected A corrupt file or configuration was not corrected. 22 | 14 Delayed An operation was delayed, for example if a restart was required to finish the operation. 23 | 15 Detected Suspicious activity or a policy violation was detected without further action. 24 | 16 No Action The outcome of an operation had no action taken. 25 | 17 Logged The operation or action was logged without further action. 26 | 18 Tagged A file or other entity was marked with extended attributes. 27 | 19 Alert The request or activity was detected as a threat and resulted in a notification but request was not blocked. 28 | 20 Count Counted the request or activity but did not determine whether to allow it or block it. 29 | 21 Reset The request was detected as a threat and resulted in the connection being reset. 30 | 22 Captcha Required the end user to solve a CAPTCHA puzzle to prove that a human being is sending the request. 31 | 23 Challenge Ran a silent challenge that required the client session to verify that it's a browser, and not a bot. 32 | 24 Access Revoked The requestor's access has been revoked due to security policy enforcements. Note: use the Host profile if the User or Actor requestor is not present in the event class. 33 | 25 Rejected A request or submission was rejected. For example, when a form was improperly filled out and submitted. This is distinct from 2 'Blocked'. 34 | 26 Unauthorized An attempt to access a resource was denied due to an authorization check that failed. This is a more specific disposition than 2 'Blocked' and can be complemented with the authorizations attribute for more detail. 35 | 27 Error An error occurred during the processing of the activity or request. Use the message attribute of the base class for details. 36 | 99 Other The disposition is not mapped. See the disposition attribute, which contains a data source specific value. 37 | """ 38 | 39 | Unknown = 0 40 | Allowed = 1 41 | Blocked = 2 42 | Quarantined = 3 43 | Isolated = 4 44 | Deleted = 5 45 | Dropped = 6 46 | CustomAction = 7 47 | Approved = 8 48 | Restored = 9 49 | Exonerated = 10 50 | Corrected = 11 51 | PartiallyCorrected = 12 52 | Uncorrected = 13 53 | Delayed = 14 54 | Detected = 15 55 | NoAction = 16 56 | Logged = 17 57 | Tagged = 18 58 | Alert = 19 59 | Count = 20 60 | Reset = 21 61 | CaptchaRequired = 22 62 | ChallengeRan = 23 63 | AccessRevoked = 24 64 | Rejected = 25 65 | Unauthorized = 26 66 | Error = 27 67 | Other = 99 68 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/finding.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | from py_ocsf_models.events.base_event import BaseEvent 7 | from py_ocsf_models.events.findings.activity_id import ActivityID 8 | from py_ocsf_models.events.findings.confidence_id import ConfidenceID 9 | from py_ocsf_models.objects.finding_info import FindingInformation 10 | 11 | 12 | class Finding(BaseEvent, BaseModel): 13 | """ 14 | The Finding event is a generic event that defines a set of attributes available in the Findings category. 15 | 16 | Attributes: 17 | - Activity (activity_name) [Optional]: The finding activity name, as defined by the activity_id. 18 | - Activity ID (activity_id): The normalized identifier of the finding activity. 19 | - Comment (comment) [Optional]: A user provided comment about the finding. 20 | - Confidence (confidence) [Optional]: The confidence, normalized to the caption of the confidence_id value. In the case of 'Other', it is defined by the event source. 21 | - Confidence ID (confidence_id) [Optional]: Represents the accuracy of the detection rule. A low confidence indicates a broad finding scope that may include benign events. 22 | - Confidence Score (confidence_score) [Optional]: The confidence score as reported by the event source. 23 | - End Time (end_time) [Optional]: Time of the latest event included in the finding. 24 | - End Time DT (end_time_dt) [Optional]: Time of the latest event included in the finding in datetime format. 25 | - Finding Information (finding_info) [Required]: Describes the supporting information about a generated finding. 26 | - Start Time (start_time) [Optional]: Time of the earliest event included in the finding. 27 | - Start Time DT (start_time_dt) [Optional]: Time of the earliest event included in the finding in datetime 28 | 29 | """ 30 | 31 | activity_name: Optional[str] 32 | activity_id: ActivityID 33 | comment: Optional[str] 34 | confidence: Optional[str] 35 | confidence_id: Optional[ConfidenceID] 36 | confidence_score: Optional[int] 37 | end_time: Optional[int] 38 | end_time_dt: Optional[datetime] 39 | finding_info: FindingInformation 40 | start_time: Optional[int] 41 | start_time_dt: Optional[datetime] 42 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/impact_id.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class ImpactID(IntEnum): 5 | """ 6 | The normalized impact of the finding. 7 | 8 | 0 Unknown: The normalized impact is unknown. 9 | 1 Low 10 | 2 Medium 11 | 3 High 12 | 4 Critical 13 | 99 Other: The impact is not mapped. See the impact attribute, which contains a data source specific value. 14 | """ 15 | 16 | Unknown = 0 17 | Low = 1 18 | Medium = 2 19 | Hig = 3 20 | Critical = 4 21 | Other = 99 22 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/risk_level_id.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class RiskLevelID(IntEnum): 5 | """ 6 | The normalized risk level id. 7 | 8 | 0 Info 9 | 1 Low 10 | 2 Medium 11 | 3 High 12 | 4 Critical 13 | """ 14 | 15 | Info = 0 16 | Low = 1 17 | Medium = 2 18 | High = 3 19 | Critical = 4 20 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/severity_id.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class SeverityID(IntEnum): 5 | """ 6 | The normalized identifier of the event/finding severity. 7 | 8 | The normalized severity is a measurement the effort and expense required to manage and resolve an event or incident. Smaller numerical values represent lower impact events, and larger numerical values represent higher impact events. 9 | 10 | 0 Unknown: The event/finding severity is unknown. 11 | 1 Informational: Informational message. No action required. 12 | 2 Low: The user decides if action is needed. 13 | 3 Medium: Action is required but the situation is not serious at this time. 14 | 4 High: Action is required immediately. 15 | 5 Critical: Action is required immediately and the scope is broad. 16 | 6 Fatal: An error occurred but it is too late to take remedial action. 17 | 99 Other: The event/finding severity is not mapped. See the severity attribute, which contains a data source specific value. 18 | """ 19 | 20 | Unknown = 0 21 | Informational = 1 22 | Low = 2 23 | Medium = 3 24 | High = 4 25 | Critical = 5 26 | Fatal = 6 27 | Other = 99 28 | -------------------------------------------------------------------------------- /py_ocsf_models/events/findings/status_id.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class StatusID(IntEnum): 5 | """ 6 | The normalized status identifier of the Finding, set by the consumer. 7 | 8 | 0 Unknown: The status is unknown. 9 | 1 New: The Finding is new and yet to be reviewed. 10 | 2 InProgress: The Finding is under review. 11 | 3 Suppressed: The Finding was reviewed, determined to be benign or a false positive and is now suppressed. 12 | 4 Resolved: The Finding was reviewed, remediated and is now considered resolved. 13 | 5 Archived: The Finding was archived. 14 | 99 Other: The event status is not mapped. See the status attribute, which contains a data source specific value. 15 | """ 16 | 17 | Unknown = 0 18 | New = 1 19 | InProgress = 2 20 | Suppressed = 3 21 | Resolved = 4 22 | Archived = 5 23 | Other = 99 24 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prowler-cloud/py-ocsf-models/96e5bb0d29f1daa37ffec6e2339777d481211951/py_ocsf_models/objects/__init__.py -------------------------------------------------------------------------------- /py_ocsf_models/objects/account.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | from typing import Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | 7 | class TypeID(IntEnum): 8 | Unknown = 0 9 | LDAP_Account = 1 10 | Windows_Account = 2 11 | AWS_IAM_User = 3 12 | AWS_IAM_Role = 4 13 | GCP_Account = 5 14 | Azure_AD_Account = 6 15 | MacOS_Account = 7 16 | Apple_Account = 8 17 | Linux_Account = 9 18 | AWS_Account = 10 19 | Other = 99 20 | 21 | 22 | class Account(BaseModel): 23 | """ 24 | The Account object contains details about the account that initiated or performed a specific activity within a system or application. 25 | 26 | Attributes: 27 | - Name (name) [Recommended]: The name of the account (e.g. GCP Account Name). 28 | - Type (type) [Optional]: The account type, normalized to the caption of 'account_type_id'. In the case of 'Other', it is defined by the event source. 29 | - Type ID (type_id) [Recommended]: The normalized account type identifier. 30 | - Unique ID (uid) [Recommended]: The unique identifier of the account (e.g. AWS Account ID). 31 | - Labels (labels) [Optional]: The labels associated with the account. 32 | 33 | """ 34 | 35 | name: str 36 | type: Optional[str] 37 | type_id: TypeID 38 | uid: str 39 | labels: Optional[list[str]] 40 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/affected_software_package.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | from typing import Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | from py_ocsf_models.objects.fingerprint import FingerPrint 7 | from py_ocsf_models.objects.remediation import Remediation 8 | 9 | 10 | class SoftwarePackageTypeID(IntEnum): 11 | Unknown = 0 12 | Application = 1 13 | Operating_System = 2 14 | Other = 99 15 | 16 | 17 | class AffectedSoftwarePackage(BaseModel): 18 | """ 19 | The Affected Package object describes details about a software package identified as affected by a vulnerability/vulnerabilities. 20 | 21 | Attributes: 22 | - Architecture (architecture) [Recommended]: Architecture is a shorthand name describing the type of computer hardware the packaged software is meant to run on. 23 | - The product CPE identifier (cpe_name) [Optional]: The Common Platform Enumeration (CPE) name as described by (NIST) For example: cpe:/a:apple:safari:16.2. 24 | - Epoch (epoch) [Optional]: Integer The software package epoch. Epoch is a way to define weighted dependencies based on version numbers. 25 | - Fixed In Version (fixed_in_version) [Optional]: The software package version in which a reported vulnerability was patched/fixed. 26 | - Hash (hash) [Optional]: Fingerprint Cryptographic hash to identify the binary instance of a software component. This can include any component such file, package, or library. 27 | - Software License (license) [Optional]: The software license applied to this package. 28 | - Software License URL (license_url) [Optional]: The URL pointing to the license applied on package or software. This is typically a LICENSE.md file within a repository. 29 | - Name (name) [Required]: The software package name. 30 | - Package Manager (package_manager) [Optional]: The software packager manager utilized to manage a package on a system, e.g. npm, yum, dpkg etc. 31 | - Package Manager URL (package_manager_url) [Optional]: The URL of the package or library at the package manager, or the specific URL or URI of an internal package manager link such as AWS CodeArtifact or Artifactory. 32 | - Path (path) [Optional]: The installation path of the affected package. 33 | - Package URL (purl) [Optional]: A purl is a URL string used to identify and locate a software package in a mostly universal and uniform way across programming languages, package managers, packaging conventions, tools, APIs and databases. 34 | - Software Release Details (release) [Optional]: Release is the number of times a version of the software has been packaged. 35 | - Remediation Guidance (remediation) [Optional]: Remediation Describes the recommended remediation steps to address identified issue(s). 36 | - Source URL (src_url) [Optional]: The link to the specific library or package such as within GitHub, this is different from the link to the package manager where the library or package is hosted. 37 | - Type (type) [Optional]: The type of software package, normalized to the caption of the type_id value. In the case of 'Other', it is defined by the source. This is the string sibling of enum attribute type_id. 38 | - Type ID (type_id) [Recommended]: Integer The type of software package. 39 | - Package UID (uid) [Optional]: A unique identifier for the package or library reported by the source tool. E.g., the libId within the sbom field of an OX Security Issue or the SPDX components.*.bom-ref. 40 | - Vendor Name (vendor_name) [Optional]: The name of the vendor who published the software package. 41 | - Version (version) [Required]: The software package version. 42 | 43 | """ 44 | 45 | architecture: Optional[str] 46 | cpe_name: Optional[str] 47 | epoch: Optional[int] 48 | fixed_in_version: Optional[str] 49 | hash: Optional[FingerPrint] 50 | license: Optional[str] 51 | license_url: Optional[str] 52 | name: str 53 | package_manager: Optional[str] 54 | package_manager_url: Optional[str] 55 | path: Optional[str] 56 | purl: Optional[str] 57 | release: Optional[str] 58 | remediation: Optional[Remediation] 59 | src_url: Optional[str] 60 | type: Optional[str] 61 | type_id: Optional[SoftwarePackageTypeID] 62 | uid: Optional[str] 63 | vendor_name: Optional[str] 64 | version: str 65 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/analytic.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class Analytic(BaseModel): 7 | """ 8 | The Analytic object contains details about the analytic technique used to analyze and derive insights from the data or information that led to the creation of a finding or conclusion. 9 | 10 | Attributes: 11 | - Category (category) [Optional]: The analytic category. 12 | - Description (desc) [Optional]: The description of the analytic that generated the finding. 13 | - Name (name) [Recommended]: The name of the analytic that generated the finding. 14 | - Type (type) [Optional]: The analytic type. 15 | - Type ID (type_id) [Required]: The analytic type ID. 16 | - Unique ID (uid) [Recommended]: The unique identifier of the analytic that generated the finding. 17 | - Version (version) [Optional]: The analytic version. For example: 1.1. 18 | """ 19 | 20 | category: Optional[str] 21 | desc: Optional[str] 22 | name: str 23 | type: Optional[str] 24 | type_id: int 25 | uid: str 26 | version: Optional[str] 27 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/api.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.objects.group import Group 6 | from py_ocsf_models.objects.request_elements import RequestElements 7 | from py_ocsf_models.objects.response_elements import ResponseElements 8 | from py_ocsf_models.objects.service import Service 9 | 10 | 11 | class API(BaseModel): 12 | """ 13 | Represents the details of an API interaction, including both request and response elements, 14 | as well as metadata about the API's operation and the service it belongs to. 15 | 16 | Attributes: 17 | - request (Optional[RequestElements]): Details pertaining to the API request. 18 | - response (Optional[ResponseElements]): Details pertaining to the API response. 19 | - group (Optional[Group]): Information about the API group, if applicable. 20 | - operation (str): The HTTP verb or operation associated with the API request, such as GET, POST, PUT, DELETE. 21 | - service (Optional[Service]): Information about the API service, including its name and other relevant details. 22 | - version (Optional[str]): The version of the API, indicating the specific iteration of the API service being used. 23 | """ 24 | 25 | request: Optional[RequestElements] 26 | response: Optional[ResponseElements] 27 | group: Optional[Group] 28 | operation: str 29 | service: Optional[Service] 30 | version: Optional[str] 31 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/assessment.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.objects.policy import Policy 6 | 7 | 8 | class Assessment(BaseModel): 9 | """ 10 | The Assessment object describes a point-in-time assessment, check, or evaluation of a specific configuration or signal against an asset, entity, person, or otherwise. For example, this can encapsulate os_signals from CrowdStrike Falcon Zero Trust Assessments, or account for Datastore configurations from Cyera, or capture details of Microsoft Intune configuration policies. 11 | 12 | Attributes: 13 | - Category (category) [Optional]: The Assessment object describes a point-in-time assessment, check, or evaluation of a specific configuration or signal against an asset, entity, person, or otherwise. For example, this can encapsulate os_signals from CrowdStrike Falcon Zero Trust Assessments, or account for Datastore configurations from Cyera, or capture details of Microsoft Intune configuration policies. 14 | - Description (desc) [Optional]: The description of the assessment criteria, or a description of the specific configuration or signal the assessment is targeting. 15 | - Meets Criteria (meets_criteria) [Optional]: Determines whether the assessment against the specific configuration or signal meets the assessments criteria. For example, if the assessment checks if a Datastore is encrypted or not, having encryption would be evaluated as true. 16 | - Name (name) [Optional]: The name of the configuration or signal being assessed. For example: Kernel Mode Code Integrity (KMCI) or publicAccessibilityState. 17 | - Policy (policy) [Optional]: The details of any policy associated with an assessment. 18 | - UID (uid) [Optional]: The unique identifier of the configuration or signal being assessed. For example: the signal_id. 19 | """ 20 | 21 | category: Optional[str] 22 | desc: Optional[str] 23 | meets_criteria: Optional[bool] 24 | name: Optional[str] 25 | policy: Optional[Policy] 26 | uid: Optional[str] 27 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/check.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.events.findings.severity_id import SeverityID 6 | from py_ocsf_models.objects.compliance_status import StatusID 7 | 8 | 9 | class Check(BaseModel): 10 | """ 11 | The check object defines a specific, testable compliance verification point that evaluates a target device against a standard, framework, or custom requirement. While checks are typically associated with formal standards (like CIS, NIST, or ISO), they can also represent custom or organizational requirements. When mapped to controls, checks can evaluate specific control_parameters to determine compliance status, but neither the control mapping nor control_parameters are required for a valid check. 12 | 13 | Attributes: 14 | - Description (desc) [Optional]: The detailed description of the compliance check, explaining the security requirement, vulnerability, or configuration being assessed. For example, CIS: The cramfs filesystem type is a compressed read-only Linux filesystem. Removing support for unneeded filesystem types reduces the local attack surface. or DISA STIG: Unauthorized access to the information system by foreign entities may result in loss or compromise of data. 15 | - Name (name) [Optional]: The name or title of the compliance check. For example, CIS: Ensure mounting of cramfs filesystems is disabled or DISA STIG: The Ubuntu operating system must implement DoD-approved encryption to protect the confidentiality of remote access sessions. 16 | 17 | - Severity (severity) [Optional]: The severity level as defined in the source document. For example CIS Benchmarks, valid values are: Level 1 (security-forward, essential settings), Level 2 (security-focused environment, more restrictive), or Scored/Not Scored (whether compliance can be automatically checked). For DISA STIG, valid values are: CAT I (maps to severity_id 5/Critical), CAT II (maps to severity_id 4/High), or CAT III (maps to severity_id 3/Medium). 18 | - Severity ID (severity_id) [Optional]: The normalized severity identifier that maps severity levels to standard severity levels. For example CIS Benchmark: Level 2 maps to 4 (High), Level 1 maps to 3 (Medium). For DISA STIG: CAT I maps to 5 (Critical), CAT II maps to 4 (High), and CAT III maps to 3 (Medium). 19 | - Standards (standards) [Optional]: The regulatory or industry standard this check is associated with. E.g., PCI DSS 3.2.1, HIPAA Security Rule, NIST SP 800-53 Rev. 5, or ISO/IEC 27001:2013. 20 | - Status (status) [Optional]: The resultant status of the compliance check normalized to the caption of the status_id value. For example, CIS Benchmark: Pass when all requirements are met, Fail when requirements are not met, or DISA STIG: NotAFinding (maps to status_id 1/Pass), Open (maps to status_id 3/Fail). 21 | - Status ID (status_id) [Optional]: The normalized status identifier of the compliance check. 22 | - UID (uid) [Optional]: The unique identifier of the compliance check within its standard or framework. For example, CIS Benchmark identifier 1.1.1.1, DISA STIG identifier V-230234, or NIST control identifier AC-17(2). 23 | - Version (version) [Optional]: The check version. For example, CIS Benchmark: 1.1.0 for Amazon Linux 2 or DISA STIG: V2R1 for Windows 10. 24 | """ 25 | 26 | desc: Optional[str] 27 | name: Optional[str] 28 | severity: Optional[str] 29 | severity_id: Optional[SeverityID] 30 | standards: Optional[List[str]] 31 | status: Optional[str] 32 | status_id: Optional[StatusID] 33 | uid: Optional[str] 34 | version: Optional[str] 35 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/cloud.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.objects.account import Account 6 | from py_ocsf_models.objects.organization import Organization 7 | 8 | 9 | class Cloud(BaseModel): 10 | """ 11 | The Cloud object contains information about a cloud account such as AWS Account ID, regions, etc. 12 | 13 | Attributes: 14 | - Account (account) [Optional]: The account object describes details about the account that was the source or target of the activity. 15 | - Network Zone (zone) [Optional]: The availability zone in the cloud region, as defined by the cloud provider. 16 | - Organization (org) [Optional]: Organization and org unit relevant to the event or object. 17 | - Project ID (project_uid) [Optional]: The unique identifier of a Cloud project. 18 | - Provider (provider) [Required]: The unique name of the Cloud services provider, such as AWS, MS Azure, GCP, etc. 19 | - Region (region) [Recommended]: The name of the cloud region, as defined by the cloud provider. 20 | """ 21 | 22 | account: Optional[Account] 23 | zone: Optional[str] 24 | org: Optional[Organization] 25 | provider: str 26 | region: Optional[str] 27 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/compliance.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.objects.assessment import Assessment 6 | from py_ocsf_models.objects.check import Check 7 | from py_ocsf_models.objects.compliance_status import StatusID 8 | 9 | 10 | class Compliance(BaseModel): 11 | """ 12 | The Compliance object contains information about Industry and Regulatory Framework standards, controls and requirements or details about custom assessments utilized in a compliance evaluation. Standards define broad security frameworks, controls represent specific security requirements within those frameworks, and checks are the testable verification points used to determine if controls are properly implemented. 13 | 14 | Attributes: 15 | - Assessments (assessments) [Optional]: A list of assessments associated with the compliance requirements evaluation. 16 | - Category (category) [Optional]: The category a control framework pertains to, as reported by the source tool, such as Asset Management or Risk Assessment. 17 | - Checks (checks) [Optional]: A list of compliance checks associated with specific industry standards or frameworks. Each check represents an individual rule or requirement that has been evaluated against a target device. Checks typically include details such as the check name (e.g., CIS: 'Ensure mounting of cramfs filesystems is disabled' or DISA STIG descriptive titles), unique identifiers (such as CIS identifier '1.1.1.1' or DISA STIG identifier 'V-230234'), descriptions (detailed explanations of security requirements or vulnerability discussions), and version information. 18 | - Control (control) [Optional]: A Control is a prescriptive, actionable set of specifications that strengthens device posture. The control specifies required security measures, while the specific implementation values are defined in control_parameters. E.g., CIS AWS Foundations Benchmark 1.2.0 - Control 2.1 - Ensure CloudTrail is enabled in all regions 19 | - Description (desc) [Optional]: The description or criteria of a control. 20 | - Requirements (requirements) [Optional]: The specific compliance requirements being evaluated. E.g., PCI DSS Requirement 8.2.3 - Passwords must meet minimum complexity requirements or HIPAA Security Rule 164.312(a)(2)(iv) - Implement encryption and decryption mechanisms 21 | - Standards (standards) [Optional]: The regulatory or industry standards being evaluated for compliance. 22 | """ 23 | 24 | assessments: Optional[List[Assessment]] 25 | category: Optional[str] 26 | checks: Optional[List[Check]] 27 | control: Optional[str] 28 | desc: Optional[str] 29 | requirements: Optional[List[str]] 30 | standards: Optional[List[str]] 31 | status_id: Optional[StatusID] 32 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/compliance_status.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class StatusID(IntEnum): 5 | """ 6 | The normalized status identifier of the compliance check. 7 | 8 | 0 Unknown: The status is unknown. 9 | 1 Pass: The compliance check passed for all the evaluated resources. 10 | 2 Warning: The compliance check did not yield a result due to missing information. 11 | 3 Fail: The compliance check failed for at least one of the evaluated resources. 12 | 99 Other: The event status is not mapped. See the status attribute, which contains a data source specific value. 13 | """ 14 | 15 | Unknown = 0 16 | Pass = 1 17 | Warning = 2 18 | Fail = 3 19 | Other = 99 20 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/container.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from uuid import UUID 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | from py_ocsf_models.objects.fingerprint import FingerPrint 7 | from py_ocsf_models.objects.image import Image 8 | 9 | 10 | class Container(BaseModel): 11 | """ 12 | Represents a container instance within a containerized application environment, detailing its image source, 13 | operational parameters, and unique identifiers. 14 | 15 | Attributes: 16 | - hash: The commit or SHA256 hash of the container image. 17 | - image: The container image details including name and potentially its tag. 18 | - tag: The image tag, specifying version, format, or OS. 19 | - name: The name of the container. 20 | - network_driver: The network driver used by the container. 21 | - orchestrator: The orchestrator managing the container. 22 | - pod_uuid: The unique identifier of the pod hosting the container. 23 | - runtime: The container runtime backend. 24 | - size: The size of the container image in bytes. 25 | - uid: The unique identifier for this container instance. 26 | """ 27 | 28 | hash: Optional[FingerPrint] 29 | image: Optional[Image] 30 | name: str 31 | network_driver: Optional[str] 32 | orchestrator: Optional[str] 33 | pod_uuid: Optional[UUID] 34 | runtime: Optional[str] 35 | size: Optional[int] 36 | uid: str 37 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/cve.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import List, Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | from py_ocsf_models.objects.cvss import CVSSScore 7 | from py_ocsf_models.objects.cwe import CWE 8 | from py_ocsf_models.objects.epss import EPSS 9 | from py_ocsf_models.objects.product import Product 10 | 11 | 12 | class CVE(BaseModel): 13 | """ 14 | Common Vulnerabilities and Exposures (CVE) details. 15 | """ 16 | 17 | created_time: Optional[datetime] 18 | cvss: Optional[list[CVSSScore]] 19 | desc: Optional[str] 20 | epss: Optional[EPSS] 21 | modified_time: Optional[datetime] 22 | product: Optional[Product] 23 | references: Optional[List[str]] 24 | related_cwes: Optional[List[CWE]] 25 | title: Optional[str] 26 | type: Optional[str] 27 | uid: str 28 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/cvss.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.objects.metric import Metric 6 | from py_ocsf_models.objects.url import URL 7 | 8 | 9 | class CVSSScore(BaseModel): 10 | """ 11 | Common Vulnerability Scoring System (CVSS) details. 12 | """ 13 | 14 | base_score: float 15 | depth: Optional[str] 16 | metrics: Optional[list[Metric]] 17 | overall_score: Optional[float] 18 | severity: Optional[str] 19 | src_url: Optional[URL] 20 | vector_string: Optional[str] 21 | vendor_name: Optional[str] 22 | version: Optional[str] 23 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/cwe.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.objects.url import URL 6 | 7 | 8 | class CWE(BaseModel): 9 | """ 10 | Common Weakness Enumeration (CWE) details. 11 | """ 12 | 13 | caption: Optional[str] 14 | src_url: Optional[URL] 15 | uid: str 16 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/device.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from enum import IntEnum 3 | from typing import List, Optional 4 | 5 | from pydantic.v1 import BaseModel 6 | 7 | from py_ocsf_models.objects.device_hardware_info import DeviceHardwareInfo 8 | from py_ocsf_models.objects.geolocation import GeoLocation 9 | from py_ocsf_models.objects.group import Group 10 | from py_ocsf_models.objects.image import Image 11 | from py_ocsf_models.objects.network_interface import NetworkInterface 12 | from py_ocsf_models.objects.operating_system import OperatingSystem 13 | from py_ocsf_models.objects.organization import Organization 14 | 15 | 16 | class DeviceType(IntEnum): 17 | """ 18 | Enum representing different types of devices. 19 | 20 | Attributes: 21 | - Unknown (0): The type is unknown. 22 | - Server (1): A server. 23 | - Desktop (2): A desktop computer. 24 | - Laptop (3): A laptop computer. 25 | - Tablet (4): A tablet computer. 26 | - Mobile (5): A mobile phone. 27 | - Virtual (6): A virtual machine. 28 | - IOT (7): An Internet of Things (IOT) device. 29 | - Browser (8): A web browser. 30 | - Firewall (9): A networking firewall. 31 | - Switch (10): A networking switch. 32 | - Hub (11): A networking hub. 33 | - Other (99): The type is not mapped. See the type attribute, which contains a data source specific value. 34 | """ 35 | 36 | Unknown = 0 37 | Server = 1 38 | Desktop = 2 39 | Laptop = 3 40 | Tablet = 4 41 | Mobile = 5 42 | Virtual = 6 43 | IOT = 7 44 | Browser = 8 45 | Firewall = 9 46 | Switch = 10 47 | Hub = 11 48 | Other = 99 49 | 50 | 51 | class RiskLevelID(IntEnum): 52 | """ 53 | Enum representing different risk level IDs. 54 | 55 | Attributes: 56 | - Info (0): Informational risk level. 57 | - Low (1): Low risk level. 58 | - Medium (2): Medium risk level. 59 | - High (3): High risk level. 60 | - Critical (4): Critical risk level. 61 | """ 62 | 63 | Info = 0 64 | Low = 1 65 | Medium = 2 66 | High = 3 67 | Critical = 4 68 | 69 | 70 | class Device(BaseModel): 71 | """ 72 | Represents a device, providing details such as hostname, IP address, operating system, etc. 73 | 74 | Attributes: 75 | - Alternate ID (uid_alt) [Optional]: An alternate unique identifier of the device, if any. 76 | - Autoscale UID (autoscale_uid) [Optional]: The unique identifier of the cloud autoscale configuration. 77 | - Compliant Device (is_compliant) [Optional]: Indicates if the event occurred on a compliant device. 78 | - Created Time (created_time) [Optional]: The time when the device was known to have been created. 79 | - Description (desc) [Optional]: The description of the device, as reported by the operating system. 80 | - Domain (domain) [Optional]: The network domain where the device resides. 81 | - First Seen (first_seen_time) [Optional]: The initial discovery time of the device. 82 | - Geo Location (location) [Optional]: The geographical location of the device. 83 | - Groups (groups) [Optional]: The group names to which the device belongs. 84 | - Hardware Info (hw_info) [Optional]: The endpoint hardware information. 85 | - Hostname (hostname) [Recommended]: The device hostname. 86 | - Hypervisor (hypervisor) [Optional]: The name of the hypervisor running on the device. 87 | - IMEI (imei) [Optional]: The International Mobile Station Equipment Identifier associated with the device. 88 | - IP Address (ip) [Recommended]: The device IP address, in either IPv4 or IPv6 format. 89 | - Image (image) [Optional]: The image used as a template to run the virtual machine. 90 | - Instance ID (instance_uid) [Recommended]: The unique identifier of a VM instance. 91 | - Last Seen (last_seen_time) [Optional]: The most recent discovery time of the device. 92 | - MAC Address (mac) [Optional]: The MAC address of the endpoint. 93 | - Managed Device (is_managed) [Optional]: Indicates if the event occurred on a managed device. 94 | - Modified Time (modified_time) [Optional]: The time when the device was last known to have been modified. 95 | - Name (name) [Recommended]: The alternate device name, ordinarily as assigned by an administrator. 96 | - Network Interface ID (interface_uid) [Recommended]: The unique identifier of the network interface. 97 | - Network Interface Name (interface_name) [Recommended]: The name of the network interface. 98 | - Network Interfaces (network_interfaces) [Optional]: The network interfaces associated with the device. 99 | - Network Zone (zone) [Optional]: The network zone or LAN segment. 100 | - OS (os) [Optional]: The endpoint operating system. 101 | - Organization (org) [Optional]: Organization and org unit related to the device. 102 | - Personal Device (is_personal) [Optional]: Indicates if the event occurred on a personal device. 103 | - Region (region) [Recommended]: The region where the virtual machine is located. 104 | - Risk Level (risk_level) [Optional]: The risk level of the device. 105 | - Risk Level ID (risk_level_id) [Optional]: The normalized risk level ID. 106 | - Risk Score (risk_score) [Optional]: The risk score as reported by the event source. 107 | - Subnet (subnet) [Optional]: The subnet mask. 108 | - Subnet UID (subnet_uid) [Optional]: The unique identifier of a virtual subnet. 109 | - Trusted Device (is_trusted) [Optional]: Indicates if the event occurred on a trusted device. 110 | - Type (type) [Optional]: The device type. 111 | - Type ID (type_id) [Required]: The device type ID. 112 | - Unique ID (uid) [Recommended]: The unique identifier of the device. 113 | - VLAN (vlan_uid) [Optional]: The Virtual LAN identifier. 114 | - VPC UID (vpc_uid) [Optional]: The unique identifier of the Virtual Private Cloud (VPC). 115 | """ 116 | 117 | uid_alt: Optional[str] 118 | autoscale_uid: Optional[str] 119 | is_compliant: Optional[bool] 120 | created_time: Optional[datetime] 121 | desc: Optional[str] 122 | domain: Optional[str] 123 | first_seen_time: Optional[datetime] 124 | location: Optional[GeoLocation] 125 | groups: Optional[List[Group]] 126 | hw_info: Optional[DeviceHardwareInfo] 127 | hostname: str 128 | hypervisor: Optional[str] 129 | imei: Optional[str] 130 | ip: str 131 | image: Optional[Image] 132 | instance_uid: Optional[str] 133 | last_seen_time: Optional[datetime] 134 | mac: Optional[str] 135 | is_managed: Optional[bool] 136 | modified_time: Optional[datetime] 137 | name: str 138 | interface_uid: Optional[str] 139 | interface_name: Optional[str] 140 | network_interfaces: Optional[List[NetworkInterface]] 141 | zone: Optional[str] 142 | os: Optional[OperatingSystem] 143 | org: Optional[Organization] 144 | is_personal: Optional[bool] 145 | region: str 146 | risk_level: Optional[str] 147 | risk_level_id: Optional[RiskLevelID] 148 | risk_score: Optional[int] 149 | subnet: Optional[str] 150 | subnet_uid: Optional[str] 151 | is_trusted: Optional[bool] 152 | type: Optional[str] 153 | type_id: DeviceType 154 | uid: str 155 | vlan_uid: Optional[str] 156 | vpc_uid: Optional[str] 157 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/device_hardware_info.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class KeyboardInformation(BaseModel): 7 | """ 8 | The Keyboard Information object contains details and attributes related to a computer or device keyboard. It encompasses information that describes the characteristics, capabilities, and configuration of the keyboard. 9 | 10 | Attributes: 11 | - Function Keys (function_keys) [Optional]: The number of function keys on the client keyboard. 12 | - IME (ime) [Optional]: The Input Method Editor (IME) file name. 13 | - Keyboard Layout (keyboard_layout) [Optional]: The keyboard locale identifier name (e.g., en-US). 14 | - Keyboard Subtype (keyboard_subtype) [Optional]: The keyboard numeric code. 15 | - Keyboard Type (keyboard_type) [Optional]: The keyboard type (e.g., xt, ico). 16 | """ 17 | 18 | function_keys: Optional[int] 19 | ime: Optional[str] 20 | keyboard_layout: Optional[str] 21 | keyboard_subtype: Optional[int] 22 | keyboard_type: Optional[str] 23 | 24 | 25 | class Display(BaseModel): 26 | """ 27 | The Display object contains information about the physical or virtual display connected to a computer system. 28 | 29 | Attributes: 30 | - Color Depth (color_depth) [Optional]: The numeric color depth. 31 | - Physical Height (physical_height) [Optional]: The numeric physical height of the display. 32 | - Physical Orientation (physical_orientation) [Optional]: The numeric physical orientation of the display. 33 | - Physical Width (physical_width) [Optional]: The numeric physical width of the display. 34 | - Scale Factor (scale_factor) [Optional]: The numeric scale factor of the display. 35 | """ 36 | 37 | color_depth: Optional[int] 38 | physical_height: Optional[int] 39 | physical_orientation: Optional[int] 40 | physical_width: Optional[int] 41 | scale_factor: Optional[int] 42 | 43 | 44 | class DeviceHardwareInfo(BaseModel): 45 | """ 46 | The Device Hardware Information object contains details and specifications of the physical components that make up a device. This information provides an overview of the hardware capabilities, configuration, and characteristics of the device. 47 | 48 | Attributes: 49 | - BIOS Date (bios_date) [Optional]: The BIOS date. 50 | - BIOS Manufacturer (bios_manufacturer) [Optional]: The BIOS manufacturer. 51 | - BIOS Version (bios_ver) [Optional]: The BIOS version. 52 | - CPU Bits (cpu_bits) [Optional]: The number of bits used for addressing in memory. 53 | - CPU Cores (cpu_cores) [Optional]: The number of processor cores in all installed processors. 54 | - CPU Count (cpu_count) [Optional]: The number of physical processors on a system. 55 | - Chassis (chassis) [Optional]: The system enclosure or physical form factor. 56 | - Desktop Display (desktop_display) [Optional]: The desktop display affiliated with the event. 57 | - Keyboard Information (keyboard_info) [Optional]: Detailed information about the keyboard. 58 | - Processor Speed (cpu_speed) [Optional]: The speed of the processor in Mhz. 59 | - Processor Type (cpu_type) [Optional]: The processor type. 60 | - RAM Size (ram_size) [Optional]: The total amount of installed RAM, in Megabytes. 61 | - Serial Number (serial_number) [Optional]: The device manufacturer serial number. 62 | """ 63 | 64 | bios_date: Optional[str] 65 | bios_manufacturer: Optional[str] 66 | bios_ver: Optional[str] 67 | cpu_bits: Optional[int] 68 | cpu_cores: Optional[int] 69 | cpu_count: Optional[int] 70 | chassis: Optional[str] 71 | desktop_display: Optional[str] 72 | keyboard_info: Optional[str] 73 | cpu_speed: Optional[int] 74 | cpu_type: Optional[str] 75 | ram_size: Optional[int] 76 | serial_number: Optional[str] 77 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/dns_query.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | from typing import Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | 7 | class DNSOpcodeID(IntEnum): 8 | """ 9 | Enum representing different DNS opcode identifiers. 10 | 11 | Attributes: 12 | - Query (0): Standard query. 13 | - Inverse Query (1): Inverse query, obsolete. 14 | - Status (2): Server status request. 15 | - Reserved (3): Reserved, not used. 16 | - Notify (4): Zone change notification. 17 | - Update (5): Dynamic DNS update. 18 | - DSO Message (6): DNS Stateful Operations (DSO). 19 | """ 20 | 21 | Query = 0 22 | Inverse_Query = 1 23 | Status = 2 24 | Reserved = 3 25 | Notify = 4 26 | Update = 5 27 | DSO_Message = 6 28 | 29 | 30 | class DNSQuery(BaseModel): 31 | """ 32 | The DNS query object represents a specific request made to the Domain Name System (DNS) to retrieve information about a domain or perform a DNS operation. 33 | This object encapsulates the necessary attributes and methods to construct and send DNS queries, specify the query type (e.g., A, AAAA, MX). 34 | 35 | Attributes: 36 | - DNS Opcode (opcode) [Optional]: The DNS opcode specifies the type of the query message. 37 | - DNS Opcode ID (opcode_id) [Recommended]: The DNS opcode ID specifies the normalized query message type. 38 | - Hostname (hostname) [Required]: The hostname or domain being queried. For example: www.example.com. 39 | - Packet UID (packet_uid) [Recommended]: The DNS packet identifier assigned by the program that generated the query. The identifier is copied to the response. 40 | - Resource Record Class (class) [Recommended]: The class of resource records being queried. See RFC1035. For example: IN. 41 | - Resource Record Type (type) [Recommended]: The type of resource records being queried. See RFC1035. For example: A, AAAA, CNAME, MX, and NS. 42 | """ 43 | 44 | opcode: Optional[str] 45 | opcode_id: Optional[DNSOpcodeID] 46 | hostname: str 47 | packet_uid: Optional[int] 48 | # TODO: Update to Pydantic v2 to use Field 49 | # class_: Optional[str] = Field( 50 | # alias="class" 51 | # ) # Renaming class to avoid conflict with Python keyword 52 | type: Optional[str] 53 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/enrichment.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class Enrichment(BaseModel): 7 | """ 8 | Represents enrichment data associated with a specific attribute, providing additional context or information. 9 | This can include various types of data, depending on the enrichment type, such as location data for an IP address. 10 | 11 | Attributes: 12 | - data (dict): The JSON-formatted enrichment data, whose structure depends on the enrichment type. 13 | - name (str): The name of the attribute being enriched. 14 | - provider (str): The name of the provider supplying the enrichment data. 15 | - type (str): The type of enrichment, indicating the nature of the data provided. 16 | - value (str): The value of the attribute to which the enrichment data pertains. 17 | """ 18 | 19 | data: dict[str, object] 20 | name: str 21 | provider: Optional[str] 22 | type: Optional[str] 23 | value: str 24 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/epss.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | 7 | class EPSS(BaseModel): 8 | """ 9 | The Exploit Prediction Scoring System (EPSS) object describes the estimated probability a vulnerability will be exploited. EPSS is a community-driven effort to combine descriptive information about vulnerabilities (CVEs) with evidence of actual exploitation in-the-wild. (EPSS). 10 | """ 11 | 12 | created_time: Optional[datetime] 13 | percentile: Optional[float] 14 | score: str 15 | version: Optional[str] 16 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/evidence_artifacts.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.objects.api import API 6 | from py_ocsf_models.objects.device import Device 7 | from py_ocsf_models.objects.dns_query import DNSQuery 8 | from py_ocsf_models.objects.resource_details import ResourceDetails 9 | from py_ocsf_models.objects.url import URL 10 | from py_ocsf_models.objects.verdict import VerdictID 11 | 12 | 13 | class EvidenceArtifacts(BaseModel): 14 | """ 15 | A collection of evidence artifacts associated to the activity/activities that triggered a security detection. 16 | 17 | 18 | Attributes: 19 | - API Details (api) [Recommended]: Describes details about the API call associated with the activity that triggered the detection. 20 | - DNS Query (query) [Recommended]: Describes details about the DNS query associated with the activity that triggered the detection. 21 | - Data (data) [Optional]: Additional evidence data that is not accounted for in the specific evidence attributes. Use only when absolutely necessary. 22 | - Device (device) [Optional]: An addressable device, computer system or host associated to the activity that triggered the detection. 23 | - Name (name) [Optional]: The naming convention or type identifier of the evidence associated with the security detection. For example, the @odata.type from Microsoft Graph Alerts V2 or display_name from CrowdStrike Falcon Incident Behaviors. 24 | - Resources (resources) [Optional]: Describes details about the cloud resources directly related to activity that triggered the detection. For resources impacted by the detection, use Affected Resources at the top-level of the finding. 25 | - URL (url) [Optional]: The URL that pertains to the event or object associated to the activity that triggered the detection. 26 | - Verdict ID (verdict_id) [Optional]: The normalized verdict (or status) ID of the evidence associated with the security detection. For example, Microsoft Graph Security Alerts contain a verdict enumeration for each type of evidence associated with the Alert. This is typically set by an automated investigation process or an analyst/investigator assigned to the finding. 27 | """ 28 | 29 | api: Optional[API] 30 | # TODO 31 | # actor: Optional[Actor] 32 | # connection_info: Optional[NetworkConnectionInformation] 33 | data: Optional[dict[str, object]] 34 | # TODO 35 | # dst_endpoint: Optional[NetworkEndpoint] 36 | # file: Optional[File] 37 | # process: Optional[Process] 38 | # src_endpoint: Optional[NetworkEndpoint] 39 | device: Optional[Device] 40 | name: Optional[str] 41 | query: Optional[DNSQuery] 42 | resources: Optional[list[ResourceDetails]] 43 | url: Optional[URL] 44 | verdict_id: Optional[VerdictID] = VerdictID.Unknown 45 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/finding_info.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import List, Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | from py_ocsf_models.objects.analytic import Analytic 7 | from py_ocsf_models.objects.kill_chain_phase import KillChainPhase 8 | from py_ocsf_models.objects.mitre_attack import MITREAttack 9 | from py_ocsf_models.objects.related_event import RelatedEvent 10 | 11 | 12 | class FindingInformation(BaseModel): 13 | """ 14 | Finding Information describes metadata related to a security finding generated by a security tool or system. 15 | 16 | Attributes: 17 | - Analytic (analytic) [Recommended]: The analytic technique used to analyze and derive insights from the data or information that led to the finding or conclusion. 18 | - Created Time (created_time) [Optional]: The time when the finding was created in datetime format. 19 | - Created Time DT (created_time_dt) [Optional]: The time when the finding was created in datetime format. 20 | - Data Sources (data_sources) [Optional]: A list of data sources utilized in generation of the finding. 21 | - Description (desc) [Optional]: The description of the reported finding. 22 | - First Seen (first_seen_time) [Optional]: The time when the finding was first observed. 23 | - First Seen DT (first_seen_time_dt) [Optional]: The time when the finding was first observed in datetime format. 24 | - Kill Chain (kill_chain) [Optional]: The Cyber Kill Chain® provides a detailed description of each phase and its associated activities within the broader context of a cyber attack. 25 | - Last Seen (last_seen_time) [Optional]: The time when the finding was last observed. 26 | - Last Seen DT (last_seen_time_dt) [Optional]: The time when the finding was last observed in datetime format. 27 | - MITRE ATT&CK® Details (attacks) [Optional]: The MITRE ATT&CK® technique and associated tactics related to the finding. 28 | - Modified Time (modified_time) [Optional]: The time when the finding was last modified. 29 | - Modified Time DT (modified_time_dt) [Optional]: The time when the finding was last modified in datetime format. 30 | - Related Analytics (related_analytics) [Optional]: Other analytics related to this finding. 31 | - Related Events (related_events) [Optional]: Describes events and/or other findings related to the finding as identified by the security product. 32 | - Source URL (src_url) [Optional]: The URL pointing to the source of the finding. 33 | - Title (title) [Required]: A title or a brief phrase summarizing the reported finding. 34 | - Types (types) [Optional]: One or more types of the reported finding. 35 | - Unique ID (uid) [Required]: The unique identifier of the reported finding. 36 | """ 37 | 38 | analytic: Optional[Analytic] 39 | created_time: Optional[int] 40 | created_time_dt: Optional[datetime] 41 | data_sources: Optional[List[str]] 42 | desc: Optional[str] 43 | first_seen_time: Optional[int] 44 | first_seen_time_dt: Optional[datetime] 45 | kill_chain: Optional[List[KillChainPhase]] 46 | last_seen_time: Optional[int] 47 | last_seen_time_dt: Optional[datetime] 48 | attacks: Optional[List[MITREAttack]] 49 | modified_time: Optional[int] 50 | modified_time_dt: Optional[datetime] 51 | related_analytics: Optional[List[Analytic]] 52 | related_events: Optional[List[RelatedEvent]] 53 | src_url: Optional[str] 54 | title: str 55 | types: Optional[List[str]] 56 | uid: str 57 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/fingerprint.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | from typing import Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | 7 | class AlgorithmID(IntEnum): 8 | """ 9 | The identifier of the normalized hash algorithm, which was used to create the digital fingerprint. 10 | 11 | 0 Unknown: The algorithm is unknown. 12 | 1 MD5: MD5 message-digest algorithm producing a 128-bit (16-byte) hash value. 13 | 2 SHA-1: Secure Hash Algorithm 1 producing a 160-bit (20-byte) hash value. 14 | 3 SHA-256: Secure Hash Algorithm 2 producing a 256-bit (32-byte) hash value. 15 | 4 SHA-512: Secure Hash Algorithm 2 producing a 512-bit (64-byte) hash value. 16 | 5 CTPH: The ssdeep generated fuzzy checksum. Also known as Context Triggered Piecewise Hash (CTPH). 17 | 6 TLSH: The TLSH fuzzy hashing algorithm. 18 | 7 quickXorHash: Microsoft simple non-cryptographic hash algorithm that works by XORing the bytes in a circular-shifting fashion. 19 | 99 Other: The algorithm is not mapped. See the algorithm attribute, which contains a data source specific value. 20 | 21 | """ 22 | 23 | Unknown = 0 24 | MD5 = 1 25 | SHA_1 = 2 26 | SHA_256 = 3 27 | SHA_512 = 4 28 | CTPH = 5 29 | TLSH = 6 30 | QuickXorHash = 7 31 | Other = 99 32 | 33 | 34 | class FingerPrint(BaseModel): 35 | """ 36 | Represents a digital fingerprint created using a specific hashing algorithm. This class 37 | encapsulates details about the algorithm used and the resulting hash value. 38 | 39 | Attributes: 40 | - Algorithm (algorithm) [Optional]: The hash algorithm used to create the digital fingerprint, normalized to the caption of 'algorithm_id'. In the case of 'Other', it is defined by the event source. 41 | - Algorithm ID (algorithm_id): The identifier of the normalized hash algorithm, which was used to create the digital fingerprint. 42 | - Value (value): The digital fingerprint value. 43 | """ 44 | 45 | algorithm: Optional[str] 46 | algorithm_id: AlgorithmID 47 | value: str 48 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/geolocation.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class GeoLocation(BaseModel): 7 | """ 8 | The GeoLocation object encapsulates geographical information about a specific location. This includes details that can be used to pinpoint a location globally, identify regional characteristics, and provide additional context about the environment of the location. 9 | 10 | Attributes: 11 | - City (city) [Recommended]: Name of the city for the location. 12 | - Continent (continent) [Recommended]: Name of the continent where the location is situated. 13 | - Coordinates (coordinates) [Recommended]: A longitude/latitude pair conforming to GeoJSON format. 14 | - Country (country) [Recommended]: ISO 3166-1 Alpha-2 country code, capitalized. 15 | - Description (desc) [Optional]: A description of the geographical location. 16 | - ISP (isp) [Optional]: Internet Service Provider associated with the location. 17 | - On Premises (is_on_premises) [Optional]: Indicates if the location is on premises. 18 | - Postal Code (postal_code) [Optional]: Postal code for the location. 19 | - Provider (provider) [Optional]: Provider of the geographical data. 20 | - Region (region) [Optional]: The principal subdivision of the country, such as a state or province. 21 | """ 22 | 23 | city: Optional[str] 24 | continent: Optional[str] 25 | coordinates: Optional[list[float]] 26 | country: Optional[str] 27 | desc: Optional[str] 28 | isp: Optional[str] 29 | is_on_premises: Optional[bool] 30 | postal_code: Optional[str] 31 | provider: Optional[str] 32 | region: Optional[str] 33 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/group.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class Group(BaseModel): 7 | """ 8 | The Group object represents a collection or association of entities, such as users, policies, or devices. It serves as a logical grouping mechanism to organize and manage entities with similar characteristics or permissions within a system or organization. 9 | 10 | Attributes: 11 | - Account Type (type) [Optional]: The type of the group or account. 12 | - Description (desc) [Optional]: The group description. 13 | - Domain (domain) [Optional]: The domain where the group is defined. For example: the LDAP or Active Directory domain. 14 | - Name (name) [Recommended]: The group name. 15 | - Privileges (privileges) [Optional]: The group privileges. 16 | - Unique ID (uid) [Recommended]: TThe unique identifier of the group. For example, for Windows events this is the security identifier (SID) of the group. 17 | """ 18 | 19 | type: Optional[str] 20 | desc: Optional[str] 21 | domain: Optional[str] 22 | name: Optional[str] 23 | privileges: Optional[list[str]] 24 | uid: Optional[str] 25 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/image.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class Image(BaseModel): 7 | """ 8 | Represents a container image, detailing its name, optional tag, labels, and unique identifier. 9 | The class encapsulates the core attributes that define a container image in a containerized environment. 10 | 11 | Attributes: 12 | - tag (Optional[str]): The image tag, specifying version or variant, e.g., '1.11-alpine'. 13 | - labels (Optional[list[str]]): Metadata labels associated with the image. 14 | - name (str): The name of the image, e.g., 'elixir'. 15 | - path (Optional[str]): The full path to the image file on the host or in the repository. 16 | - uid (str): A unique identifier for the image, e.g., '77af4d6b9913'. 17 | """ 18 | 19 | tag: Optional[str] 20 | labels: Optional[list[str]] 21 | name: str 22 | path: Optional[str] 23 | uid: str 24 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/kb_article.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | from py_ocsf_models.objects.operating_system import OperatingSystem 7 | from py_ocsf_models.objects.product import Product 8 | 9 | 10 | class KBArticle(BaseModel): 11 | """ 12 | Describes a knowledgebase article, providing essential information such as its classification, 13 | release date, applicable operating system, and severity. It includes details like the article's 14 | size, source URL, and whether it has been superseded by another patch. 15 | 16 | Attributes: 17 | - classification: Vendor's classification of the KB article. 18 | - created_time: Time the KB article was created. 19 | - created_time_dt: Time the KB article was created in datetime 20 | - os: Operating system the KB article applies to. 21 | - bulletin: Bulletin identifier of the KB article. 22 | - product: Product details the KB article applies to. 23 | - severity: Severity rating of the KB article. 24 | - size: Size of the KB article in bytes. 25 | - src_url: Link to the KB article from the vendor. 26 | - is_superseded: Indicates if the article has been replaced by another. 27 | - title: Title of the KB article. 28 | - uid: Unique identifier for the KB article. 29 | """ 30 | 31 | classification: Optional[str] 32 | created_time: Optional[int] 33 | created_time_dt: Optional[datetime] 34 | os: OperatingSystem 35 | bulletin: Optional[str] 36 | product: Optional[Product] 37 | severity: str 38 | size: Optional[int] 39 | src_url: Optional[str] 40 | is_superseded: Optional[bool] 41 | title: str 42 | uid: str 43 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/kill_chain_phase.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class PhaseID(IntEnum): 7 | """ 8 | The Kill Chain Phase object represents a single phase of a cyber attack, including the initial reconnaissance and planning stages up to the final objective of the attacker. It provides a detailed description of each phase and its associated activities within the broader context of a cyber attack. 9 | 10 | Attributes: 11 | - Unknown (0): The kill chain phase is unknown. 12 | - Reconnaissance (1): The attackers pick a target and perform a detailed analysis, start collecting information (email addresses, conferences information, etc.) and evaluate the victim’s vulnerabilities to determine how to exploit them. 13 | - Weaponization (2): The attackers develop a malware weapon and aim to exploit the discovered vulnerabilities. 14 | - Delivery (3): The intruders will use various tactics, such as phishing, infected USB drives, etc. 15 | - Exploitation (4): The intruders start leveraging vulnerabilities to executed code on the victim’s system. 16 | - Installation (5): The intruders install malware on the victim’s system. 17 | - Command & Control (6): Malware opens a command channel to enable the intruders to remotely manipulate the victim's system. 18 | - Actions on Objectives (7): With hands-on keyboard access, intruders accomplish the mission’s goal. 19 | - Other (99): The kill chain phase is not mapped. See the phase attribute, which contains a data source specific value. 20 | """ 21 | 22 | Unknown = 0 23 | Reconnaissance = 1 24 | Weaponization = 2 25 | Delivery = 3 26 | Exploitation = 4 27 | Installation = 5 28 | Command_Control = 6 29 | Actions_on_Objectives = 7 30 | Other = 99 31 | 32 | 33 | class KillChainPhase(BaseModel): 34 | """ 35 | Base model representing a Cyber Kill Chain phase. 36 | 37 | Attributes: 38 | - Kill Chain Phase (phase) [Recommended]: The cyber kill chain phase. 39 | - Kill Chain Phase ID (phase_id) [Required]: The cyber kill chain phase identifier. 40 | """ 41 | 42 | phase: str 43 | phase_id: PhaseID 44 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/ldap_person.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | # FIXME(circular-dependency) 5 | # from py_ocsf_models.objects.user import User 6 | from pydantic.v1 import BaseModel, EmailStr 7 | 8 | from py_ocsf_models.objects.geolocation import GeoLocation 9 | 10 | 11 | class LDAPPerson(BaseModel): 12 | """ 13 | The LDAPPerson class encapsulates detailed information about an individual within an LDAP or Active Directory system. It is designed to model both the professional and personal attributes of a person, including their role, contact information, and organizational context. 14 | 15 | Attributes: 16 | - Cost Center (cost_center) [Optional]: Associated cost center for budgeting and financial analysis. 17 | - Created Time (created_time) [Optional]: Timestamp of when the user account was created. 18 | - Deleted Time (deleted_time) [Optional]: Timestamp indicating when the user was deleted, useful in AD environments. 19 | - Email Addresses (email_addrs) [Optional]: list of additional email addresses. 20 | - Employee ID (employee_uid) [Optional]: Unique identifier assigned by the organization. 21 | - Geo Location (location) [Optional]: Usual work location of the user. 22 | - Given Name (given_name) [Optional]: First name of the user. 23 | - Hire Time (hire_time) [Optional]: Timestamp when the user was hired. 24 | - Job Title (job_title) [Optional]: Official job title. 25 | - LDAP Common Name (ldap_cn) [Optional]: Full name as per LDAP cn attribute. 26 | - LDAP Distinguished Name (ldap_dn) [Optional]: Unique DN in the LDAP directory. 27 | - Labels (labels) [Optional]: Array of labels or tags associated with the user. 28 | - Last Login (last_login_time) [Optional]: Last login timestamp. 29 | - Leave Time (leave_time) [Optional]: When the user left or will leave the organization. 30 | - Manager (manager) [Optional]: Direct manager, supports org hierarchy. 31 | - Modified Time (modified_time) [Optional]: Last modification timestamp of the user entry. 32 | - Office Location (office_location) [Optional]: Primary office location, not necessarily a specific address. 33 | - Surname (surname) [Optional]: Family or last name. 34 | """ 35 | 36 | cost_center: Optional[str] 37 | created_time: Optional[datetime] 38 | deleted_time: Optional[datetime] 39 | email_addrs: Optional[list[EmailStr]] 40 | employee_uid: Optional[str] 41 | location: Optional[GeoLocation] 42 | given_name: Optional[str] 43 | hire_time: Optional[datetime] 44 | job_title: Optional[str] 45 | ldap_cn: Optional[str] 46 | ldap_dn: Optional[str] 47 | labels: Optional[list[str]] 48 | last_login_time: Optional[datetime] 49 | leave_time: Optional[datetime] 50 | # FIXME(circular-dependency) 51 | # manager: Optional[User] 52 | modified_time: Optional[datetime] 53 | office_location: Optional[str] 54 | surname: Optional[str] 55 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/metadata.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import List, Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | from py_ocsf_models import OCSF_VERSION 7 | from py_ocsf_models.objects.device import Device 8 | from py_ocsf_models.objects.product import Product 9 | 10 | 11 | class SchemaExtension(BaseModel): 12 | """ 13 | The OCSF Schema Extension object provides detailed information about the schema extension used to construct the event. 14 | 15 | Attributes: 16 | - Name (name) [Required]: The schema extension name (e.g., dev). 17 | - Unique ID (uid) [Required]: The unique identifier of the schema extension (e.g., 999). 18 | - Version (version) [Required]: The version of the schema extension (e.g., 1.0.0-alpha.2). 19 | """ 20 | 21 | name: str 22 | uid: str 23 | version: str 24 | 25 | 26 | class Logger(BaseModel): 27 | """ 28 | The Logger object represents the device and product where events are stored with times for receipt and transmission. This may be at the source device where the event occurred, a remote scanning device, intermediate hops, or the ultimate destination. 29 | 30 | Attributes: 31 | - Device (device) [Recommended]: The device where the events are logged. 32 | - Log Level (log_level) [Optional]: The audit level at which an event was generated. 33 | - Log Name (log_name) [Recommended]: The event log name (e.g., syslog file name or Windows logging subsystem: Security). 34 | - Log Provider (log_provider) [Recommended]: The logging provider or logging service that logged the event (e.g., Microsoft-Windows-Security-Auditing). 35 | - Log Version (log_version) [Optional]: The event log schema version that specifies the format of the original event. 36 | - Logged Time (logged_time) [Optional]: The time when the logging system collected and logged the event. 37 | - Name (name) [Recommended]: The name of the logging product instance. 38 | - Product (product) [Recommended]: The product logging the event (e.g., event source product, management server product, SIEM, etc.). 39 | - Transmission Time (transmit_time) [Optional]: The time when the event was transmitted from the logging device to its next destination. 40 | - Unique ID (uid) [Recommended]: The unique identifier of the logging product instance. 41 | - Version (version) [Optional]: The version of the logging product. 42 | """ 43 | 44 | device: Optional[Device] 45 | log_level: Optional[str] 46 | log_name: str 47 | log_provider: str 48 | log_version: Optional[str] 49 | logged_time: Optional[datetime] 50 | name: str 51 | product: Product 52 | transmit_time: Optional[datetime] 53 | uid: str 54 | version: Optional[str] 55 | 56 | 57 | class Metadata(BaseModel): 58 | """ 59 | The Metadata object describes the metadata associated with the event. 60 | 61 | Attributes: 62 | - Correlation UID (correlation_uid) [Optional]: Unique identifier used to correlate events. 63 | - Event Code (event_code) [Optional]: The Event ID or Code describing the event. 64 | - Event UID (uid) [Optional]: Logging system-assigned unique identifier of an event instance. 65 | - Labels (labels) [Optional]: List of category labels attached to the event or specific attributes. 66 | - Log Level (log_level) [Optional]: Audit level at which the event was generated. 67 | - Log Name (log_name) [Optional]: Event log name (e.g., syslog file name or Windows logging subsystem). 68 | - Log Provider (log_provider) [Optional]: Logging provider or service that logged the event. 69 | - Log Version (log_version) [Optional]: Event log schema version specifying the format of the original event. 70 | - Logged Time (logged_time) [Optional]: Time when the logging system collected and logged the event. 71 | - Loggers (loggers) [Optional]: Array of Logger objects describing the devices and logging products in the event flow. 72 | - Modified Time (modified_time) [Optional]: Time when the event was last modified or enriched. 73 | - Original Time (original_time) [Optional]: Original event time as reported by the event source. 74 | - Processed Time (processed_time) [Optional]: Event processed time, such as during an ETL operation. 75 | - Product (product) [Required]: Product that reported the event. 76 | - Profiles (profiles) [Optional]: List of profiles used to create the event. 77 | - Extensions (extensions) [Optional]: Schema extensions used to create the event. 78 | - Sequence (sequence) [Optional]: Sequence number of the event for unambiguous ordering. 79 | - Tenant UID (tenant_uid) [Optional]: Unique tenant identifier. 80 | - Version (version) [Required]: Version of the OCSF schema in Semantic Versioning Specification (SemVer). 81 | """ 82 | 83 | correlation_uid: Optional[str] 84 | event_code: Optional[str] 85 | uid: Optional[str] 86 | labels: Optional[List[str]] 87 | log_level: Optional[str] 88 | log_name: Optional[str] 89 | log_provider: Optional[str] 90 | log_version: Optional[str] 91 | logged_time: Optional[datetime] 92 | loggers: Optional[List[Logger]] 93 | modified_time: Optional[datetime] 94 | original_time: Optional[str] 95 | processed_time: Optional[datetime] 96 | product: Product 97 | profiles: Optional[List[str]] 98 | extensions: Optional[List[SchemaExtension]] 99 | sequence: Optional[int] 100 | tenant_uid: Optional[str] 101 | version: str = OCSF_VERSION 102 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/metric.py: -------------------------------------------------------------------------------- 1 | from pydantic.v1 import BaseModel 2 | 3 | 4 | class Metric(BaseModel): 5 | """ 6 | The Metric object defines a simple name/value pair entity for a metric. 7 | """ 8 | 9 | name: str 10 | value: str 11 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/mitre_attack.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class Technique(BaseModel): 7 | """ 8 | The Technique object describes the technique ID and/or name associated to an attack, as defined by ATT&CK MatrixTM. 9 | 10 | 11 | Attributes: 12 | - Name (name) [Recommended]: The name of the attack technique, as defined by ATT&CK MatrixTM. 13 | - Source URL (src_url) [Optional]: The versioned permalink of the attack technique, as defined by ATT&CK MatrixTM. 14 | - Unique ID (uid) [Recommended]: The unique identifier of the attack technique, as defined by ATT&CK MatrixTM. 15 | """ 16 | 17 | name: str 18 | src_url: Optional[str] 19 | uid: str 20 | 21 | 22 | class Tactic(BaseModel): 23 | """ 24 | The Tactic object describes the tactic ID and/or name that is associated to an attack, as defined by ATT&CK MatrixTM. 25 | 26 | 27 | Attributes: 28 | - Name (name) [Optional]: The tactic name that is associated with the attack technique, as defined by ATT&CK MatrixTM. For example: Reconnaissance. 29 | - Source URL (src_url) [Optional]: The versioned permalink of the attack tactic, as defined by ATT&CK MatrixTM. For example: https://attack.mitre.org/versions/v14/tactics/TA0043/. 30 | - Unique ID (uid) [Recommended]: The tactic ID that is associated with the attack technique, as defined by ATT&CK MatrixTM. For example: TA0043. 31 | """ 32 | 33 | name: Optional[str] 34 | src_url: Optional[str] 35 | uid: Optional[str] 36 | 37 | 38 | class SubTechnique(BaseModel): 39 | """ 40 | The Sub Technique object describes the sub technique ID and/or name associated to an attack, as defined by ATT&CK MatrixTM. 41 | 42 | 43 | Attributes: 44 | - Name (name) [Optional]: The name of the attack sub technique, as defined by ATT&CK MatrixTM. For example: Scanning IP Blocks. 45 | - Source URL (src_url) [Optional]: The versioned permalink of the attack sub technique, as defined by ATT&CK MatrixTM. For example: https://attack.mitre.org/versions/v14/techniques/T1595/001/. 46 | - Unique ID (uid) [Recommended]: The unique identifier of the attack sub technique, as defined by ATT&CK MatrixTM. For example: T1595.001. 47 | """ 48 | 49 | name: Optional[str] 50 | src_url: Optional[str] 51 | uid: Optional[str] 52 | 53 | 54 | class MITREAttack(BaseModel): 55 | """ 56 | The MITRE ATT&CK® object describes the tactic, technique & sub-technique associated to an attack as defined in ATT&CK MatrixTM. 57 | 58 | Attributes: 59 | - Sub Technique (sub_technique) [Optional]: The Sub Technique object describes the sub technique ID and/or name associated to an attack, as defined by ATT&CK MatrixTM. 60 | - Tactic (tactic) [Optional]: The Tactic object describes the tactic ID and/or name that is associated to an attack, as defined by ATT&CK MatrixTM. 61 | - Technique (technique) [Optional]: The Technique object describes the technique ID and/or name associated to an attack, as defined by ATT&CK MatrixTM. 62 | - Version (version) [Recommended]: The ATT&CK MatrixTM version. 63 | """ 64 | 65 | sub_technique: Optional[SubTechnique] 66 | tactic: Optional[Tactic] 67 | technique: Optional[Technique] 68 | version: Optional[str] 69 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/network_interface.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | from typing import Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | 7 | class NetworkType(IntEnum): 8 | """ 9 | Enum representing different types of network interfaces. 10 | 11 | Attributes: 12 | - Unknown (0): The type is unknown. 13 | - Wired (1): A wired network interface. 14 | - Wireless (2): A wireless network interface. 15 | - Mobile (3): A mobile network interface. 16 | - Tunnel (4): A tunnel network interface. 17 | - Other (99): The type is not mapped. See the type attribute, which contains a data source specific value. 18 | """ 19 | 20 | Unknown = 0 21 | Wired = 1 22 | Wireless = 2 23 | Mobile = 3 24 | Tunnel = 4 25 | Other = 99 26 | 27 | 28 | class NetworkInterface(BaseModel): 29 | """ 30 | The Network Interface object describes the type and associated attributes of a network interface. 31 | 32 | Attributes: 33 | - Hostname (hostname) [Recommended]: The hostname associated with the network interface. 34 | - IP Address (ip) [Recommended]: The IP address associated with the network interface. 35 | - MAC Address (mac) [Recommended]: The MAC address of the network interface. 36 | - Name (name) [Recommended]: The name of the network interface. 37 | - Namespace (namespace) [Optional]: The namespace useful in merger or acquisition situations. 38 | - Subnet Prefix Length (subnet_prefix) [Optional]: The subnet prefix length determines the number of bits used to represent the network part of the IP address. 39 | - Type (type) [Optional]: The type of network interface. 40 | - Type ID (type_id) [Required]: The network interface type identifier. 41 | - Unique ID (uid) [Optional]: The unique identifier for the network interface. 42 | """ 43 | 44 | hostname: str 45 | ip: str 46 | mac: str 47 | name: str 48 | namespace: Optional[str] 49 | subnet_prefix: Optional[int] 50 | type: Optional[str] 51 | type_id: NetworkType 52 | uid: Optional[str] 53 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/observable.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | from typing import Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | 7 | class ReputationScoreID(IntEnum): 8 | """ 9 | Enum representing different reputation score identifiers. 10 | 11 | Attributes: 12 | - Unknown (0): The reputation score is unknown. 13 | - Very Safe (1): Long history of good behavior. 14 | - Safe (2): Consistently good behavior. 15 | - Probably Safe (3): Reasonable history of good behavior. 16 | - Leans Safe (4): Starting to establish a history of normal behavior. 17 | - May not be Safe (5): No established history of normal behavior. 18 | - Exercise Caution (6): Starting to establish a history of suspicious or risky behavior. 19 | - Suspicious/Risky (7): A site with a history of suspicious or risky behavior (spam, scam, potentially unwanted software, potentially malicious). 20 | - Possibly Malicious (8): Strong possibility of maliciousness. 21 | - Probably Malicious (9): Indicators of maliciousness. 22 | - Malicious (10): Proven evidence of maliciousness. 23 | - Other (99): The reputation score is not mapped. See the rep_score attribute, which contains a data source specific value. 24 | """ 25 | 26 | Unknown = 0 27 | Very_Safe = 1 28 | Safe = 2 29 | Probably_Safe = 3 30 | Leans_Safe = 4 31 | May_not_be_Safe = 5 32 | Exercise_Caution = 6 33 | Suspicious_or_Risky = 7 34 | Possibly_Malicious = 8 35 | Probably_Malicious = 9 36 | Malicious = 10 37 | Other = 99 38 | 39 | 40 | class Reputation(BaseModel): 41 | """ 42 | BaseModel class for representing reputation information. 43 | 44 | Attributes: 45 | - Provider (provider) [Recommended]: The provider of the reputation information. 46 | - Reputation Score (base_score) [Required]: The reputation score as reported by the event source. 47 | - Reputation Score (score) [Optional]: The reputation score, normalized to the caption of the score_id value. In the case of 'Other', it is defined by the event source. 48 | - Reputation Score ID (score_id) [Required]: The normalized reputation score identifier. 49 | """ 50 | 51 | provider: str 52 | base_score: float 53 | score: Optional[str] 54 | score_id: ReputationScoreID 55 | 56 | 57 | class TypeID(IntEnum): 58 | """ 59 | Enum representing different types of observable value identifiers. 60 | 61 | Attributes: 62 | - Unknown (0): Unknown observable data type. 63 | - Hostname (1): Unique name assigned to a device connected to a computer network. A domain name in general is an Internet address that can be resolved through the Domain Name System (DNS). 64 | - IP_Address (2): Internet Protocol address (IP address), in either IPv4 or IPv6 format. 65 | - MAC_Address (3): Media Access Control (MAC) address. 66 | - User_Name (4): User name. 67 | - Email_Address (5): Email address. 68 | - URL_String (6): Uniform Resource Locator (URL) string. 69 | - File_Name (7): File name. 70 | - Hash (8): Hash. A unique value that corresponds to the content of the file, image, ja3_hash or hassh found in the schema. 71 | - Process_Name (9): Process name. 72 | - Resource_UID (10): Resource unique identifier. For example, S3 Bucket name or EC2 Instance ID. 73 | - Endpoint (20): The Endpoint object describes a physical or virtual device that connects to and exchanges information with a computer network. Some examples of endpoints are mobile devices, desktop computers, virtual machines, embedded devices, and servers. Internet-of-Things devices—like cameras, lighting, refrigerators, security systems, smart speakers, and thermostats—are also endpoints. 74 | - User (21): The User object describes the characteristics of a user/person or a security principal. Defined by D3FEND d3f:UserAccount. 75 | - Email (22): The Email object describes the email metadata such as sender, recipients, and direction. Defined by D3FEND d3f:Email. 76 | - Uniform_Resource_Locator (23): The Uniform Resource Locator (URL) object describes the characteristics of a URL. Defined in RFC 1738 and by D3FEND d3f:URL. 77 | - File (24): The File object represents the metadata associated with a file stored in a computer system. It encompasses information about the file itself, including its attributes, properties, and organizational details. Defined by D3FEND d3f:File. 78 | - Process (25): The Process object describes a running instance of a launched program. Defined by D3FEND d3f:Process. 79 | - Geo_Location (26): The Geo Location object describes a geographical location, usually associated with an IP address. Defined by D3FEND d3f:PhysicalLocation. 80 | - Container (27): The Container object describes an instance of a specific container. A container is a prepackaged, portable system image that runs isolated on an existing system using a container runtime like containerd. 81 | - Registry_Key (28): The registry key object describes a Windows registry key. Defined by D3FEND d3f:WindowsRegistryKey. 82 | - Registry_Value (29): The registry value object describes a Windows registry value. 83 | - Fingerprint (30): The Fingerprint object provides detailed information about a digital fingerprint, which is a compact representation of data used to identify a longer piece of information, such as a public key or file content. It contains the algorithm and value of the fingerprint, enabling efficient and reliable identification of the associated data. 84 | - Other (99): The observable data type is not mapped. See the type attribute, which may contain data source specific value. 85 | """ 86 | 87 | Unknown = 0 88 | Hostname = 1 89 | IP_Address = 2 90 | MAC_Address = 3 91 | User_Name = 4 92 | Email_Address = 5 93 | URL_String = 6 94 | File_Name = 7 95 | Hash = 8 96 | Process_Name = 9 97 | Resource_UID = 10 98 | Endpoint = 20 99 | User = 21 100 | Email = 22 101 | Uniform_Resource_Locator = 23 102 | File = 24 103 | Process = 25 104 | Geo_Location = 26 105 | Container = 27 106 | Registry_Key = 28 107 | Registry_Value = 29 108 | Fingerprint = 30 109 | Other = 99 110 | 111 | 112 | class Observable(BaseModel): 113 | """ 114 | The observable object is a pivot element that contains related information found in many places in the event. 115 | 116 | Attributes: 117 | - Name (name): The full name of the observable attribute. The name is a pointer/reference to an attribute within the event data. For example: file.name. 118 | - Reputation Scores (reputation) [Optional]: Contains the original and normalized reputation scores. 119 | - Type (type) [Optional]: The observable value type name. 120 | - Type ID (type_id): The observable value type identifier. 121 | - Value (value) [Optional]: The value associated with the observable attribute. The meaning of the value depends on the observable type. If the name refers to a scalar attribute, then the value is the value of the attribute. If the name refers to an object attribute, then the value is not populated. 122 | """ 123 | 124 | name: str 125 | reputation: Optional[Reputation] 126 | type: Optional[str] 127 | type_id: TypeID 128 | value: Optional[str] 129 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/operating_system.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | from typing import Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | 7 | class TypeID(IntEnum): 8 | Unknown = 0 9 | Other = 99 10 | Windows = 100 11 | Windows_Mobile = 101 12 | Linux = 200 13 | Android = 201 14 | MacOS = 300 15 | IOS = 301 16 | IPadOS = 302 17 | Solaris = 400 18 | AIX = 401 19 | HP_UX = 402 20 | 21 | 22 | class OperatingSystem(BaseModel): 23 | """ 24 | Represents the operating system, detailing its architecture, country, language, name, build, and specific editions or service packs. 25 | It encompasses both broad categorization and specific identifiers like CPE names. 26 | 27 | Attributes: 28 | - CPU Bits (cpu_bits) [Optional]: The cpu architecture, the number of bits used for addressing in memory. For example: 32 or 64. 29 | - Country (country) [Optional]: The operating system country code, as defined by the ISO 3166-1 standard (Alpha-2 code). For the complete list of country codes, see ISO 3166-1 alpha-2 codes. 30 | - Language (lang) [Optional]: The two letter lower case language codes, as defined by ISO 639-1. For example: en (English), de (German), or fr (French). 31 | - Name (name) [Optional]: The operating system name. 32 | - OS Build (build) [Optional]: The operating system build number. 33 | - OS Edition (edition) [Optional]: The operating system edition. For example: Professional. 34 | - OS Service Pack Name (sp_name) [Optional]: The name of the latest Service Pack. 35 | - OS Service Pack Version (sp_ver) [Optional]: The version number of the latest Service Pack. 36 | - The product CPE identifier (cpe_name) [Optional]: The Common Platform Enumeration (CPE) name as described by (NIST) For example: cpe:/a:apple:safari:16.2. 37 | - Type (type) [Optional]: The type of the operating system. 38 | - Type ID (type_id) [Optional]: The type identifier of the operating system. 39 | - Version (version) [Optional]: The version of the OS running on the device that originated the event. For example: "Windows 10", "OS X 10.7", or "iOS 9". 40 | """ 41 | 42 | cpu_bits: Optional[int] 43 | country: Optional[str] 44 | lang: Optional[str] 45 | name: str 46 | build: Optional[str] 47 | edition: Optional[str] 48 | sp_name: Optional[str] 49 | sp_ver: Optional[int] 50 | cpe_name: Optional[str] 51 | type: Optional[str] 52 | type_id: TypeID 53 | version: Optional[str] 54 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/organization.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class Organization(BaseModel): 7 | """ 8 | The Organization object describes characteristics of an organization or company and its division if any. 9 | 10 | Attributes: 11 | - Name (name): The name of the organization. For example, Widget, Inc. 12 | - Org Unit ID (ou_uid) [Optional]: The alternate identifier for an entity's unique identifier. For example, its Active Directory OU DN or AWS OU ID 13 | - Org Unit Name (ou_name): The name of the organizational unit, within an organization. For example, Finance, IT, R&D 14 | - Unique ID (uid): The unique identifier of the organization. For example, its Active Directory or AWS Org ID. 15 | """ 16 | 17 | name: Optional[str] 18 | ou_uid: Optional[str] 19 | ou_name: Optional[str] 20 | uid: Optional[str] 21 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/policy.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class Policy(BaseModel): 7 | """ 8 | The Policy object describes the policies that are applicable. Policy attributes provide traceability to the operational state of the security product at the time that the event was captured, facilitating forensics, troubleshooting, and policy tuning/adjustments. 9 | 10 | Attributes: 11 | - Data (data) [Optional]: Additional data about the policy such as the underlying JSON policy itself or other details. 12 | - Description (desc) [Optional]: The description of the policy. 13 | - Group (group) [Optional]: The policy group. 14 | - Is Applied (is_applied) [Optional]: A determination if the content of a policy was applied to a target or request, or not. 15 | - Name (name) [Optional]: The policy name. For example: IAM Policy. 16 | - UID (uid) [Optional]: A unique identifier of the policy instance. 17 | - Version (version) [Optional]: The policy version number. 18 | """ 19 | 20 | data: Optional[str] 21 | desc: Optional[str] 22 | group: Optional[str] 23 | is_applied: Optional[bool] 24 | name: Optional[str] 25 | uid: Optional[str] 26 | version: Optional[str] 27 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/product.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class Feature(BaseModel): 7 | """ 8 | The Feature object provides information about the software product feature that generated a specific event. It encompasses details related to the capabilities, components, user interface (UI) design, and performance upgrades associated with the feature. 9 | 10 | Attributes: 11 | - Name (name) [Optional]: The name of the feature. 12 | - Unique ID (uid) [Optional]: The unique identifier for the feature. 13 | - Version (version) [Optional]: The version of the feature. 14 | """ 15 | 16 | name: Optional[str] 17 | uid: Optional[str] 18 | version: Optional[str] 19 | 20 | 21 | class Product(BaseModel): 22 | """ 23 | The Product object describes characteristics of a software product. 24 | 25 | Attributes: 26 | - Feature (name) [Optional]: The feature that reported the event. 27 | - Language (lang) [Optional]: The two letter lower case language codes, as defined by ISO 639-1. For example: en (English), de (German), or fr (French). 28 | - Name (name) [Optional]: The name of the product. 29 | - Path (path) [Optional]: The installation path of the product. 30 | - The product CPE identifier (cpe_name) [Optional]: The Common Platform Enumeration (CPE) name as described by (NIST) For example: cpe:/a:apple:safari:16.2. 31 | - URL String (url_string) [Optional]: The URL pointing towards the product. 32 | - Unique ID (uid) [Optional]: The unique identifier of the product. 33 | - Vendor Name (vendor_name) [Optional]: The name of the vendor of the product. 34 | - Version (version) [Optional]: The version of the product, as defined by the event source. For example: 2013.1.3-beta. 35 | """ 36 | 37 | feature: Optional[Feature] 38 | lang: Optional[str] 39 | name: Optional[str] 40 | path: Optional[str] 41 | cpe_name: Optional[str] 42 | url_string: Optional[str] 43 | uid: Optional[str] 44 | vendor_name: str 45 | version: Optional[str] 46 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/related_event.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.objects.mitre_attack import MITREAttack 6 | from py_ocsf_models.objects.observable import Observable 7 | 8 | 9 | class RelatedEvent(BaseModel): 10 | """ 11 | Model representing a related event. 12 | 13 | The RelatedEvent class encapsulates information about an event related to a security incident, 14 | including details such as the Cyber Kill Chain phase, MITRE ATT&CK® details, observables, 15 | product identifier, event type, event type identifier, and unique identifier. 16 | 17 | Attributes: 18 | - Kill Chain (kill_chain) [Optional]: The Cyber Kill Chain® provides a detailed description of each phase and its associated activities within the broader context of a cyber attack. 19 | - MITRE ATT&CK® Details (attacks) [Optional]: An array of MITRE ATT&CK® objects describing the tactics, techniques & sub-techniques identified by a security control or finding. 20 | - Observables (observables) [Optional]: The observables associated with the event or a finding. 21 | - Type (type) [Optional]: The type of the related event. For example: Process Activity: Launch. 22 | - Type ID (type_uid) [Recommended]: The unique identifier of the related event type. For example: 100701. 23 | - Unique ID (uid) [Required]: The unique identifier of the related event. 24 | """ 25 | 26 | # TODO 27 | # kill_chain: Optional[List[KillChainPhase]] 28 | attacks: Optional[List[MITREAttack]] 29 | observables: Optional[List[Observable]] 30 | type: Optional[str] 31 | type_uid: Optional[int] 32 | uid: str 33 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/remediation.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.objects.kb_article import KBArticle 6 | 7 | 8 | class Remediation(BaseModel): 9 | """ 10 | Describes the remediation strategy for addressing findings, including detailed descriptions, related knowledgebase (KB) articles, 11 | and external references. This class supports comprehensive remediation planning and documentation. 12 | 13 | Attributes: 14 | - desc (str): Detailed description of the remediation strategy. 15 | - kb_article_list (Optional[list[KBArticle]]): A list of KB articles describing patches or updates related to the remediation. 16 | - references (Optional[list[str]]): URLs or references supporting the described remediation strategy. 17 | """ 18 | 19 | desc: str 20 | kb_article_list: Optional[list[KBArticle]] 21 | references: Optional[list[str]] 22 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/request_elements.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.objects.container import Container 6 | 7 | 8 | class RequestElements(BaseModel): 9 | """ 10 | Represents the elements of an API request, especially in containerized applications. 11 | It includes details about the containers involved, any additional data associated with the request, 12 | communication flags, and a unique identifier for the request. 13 | 14 | Attributes: 15 | - containers: An array of containers involved in the API request/response process. 16 | - data: Additional JSON-formatted data associated with the API request. 17 | - flags: A list of communication flags indicating specific characteristics or behaviors of the request. 18 | - uid: A unique identifier for the API request. 19 | """ 20 | 21 | containers: Optional[list[Container]] 22 | data: Optional[dict[str, object]] 23 | flags: Optional[list[str]] 24 | uid: str 25 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/resource_details.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.objects.group import Group 6 | from py_ocsf_models.objects.user import User 7 | 8 | 9 | class ResourceDetails(BaseModel): 10 | """ 11 | The Resource Details object describes details about resources that were affected by the activity/event. 12 | 13 | Attributes: 14 | - Criticality (criticality) [Optional]: The criticality of the resource as defined by the event source. 15 | - Data (data) [Optional]: Additional data describing the resource. 16 | - Group (group) [Optional]: The name of the related resource group. 17 | - Labels (labels) [Optional]: The list of labels/tags associated to a resource. 18 | - Name (name) [Optional]: The name of the resource. 19 | - Namespace (namespace) [Optional]: The namespace is useful when similar entities exist that you need to keep separate. 20 | - Owner (owner) [Recommended]: The identity of the service or user account that owns the resource. 21 | - Type (type) [Optional]: The resource type as defined by the event source. 22 | - Unique ID (uid) [Optional]: The unique identifier of the resource. 23 | - Version (version) [Optional]: The version of the resource. For example 1.2.3. 24 | 25 | If Cloud profile: 26 | - Cloud Partition (cloud_partition) [Optional]: The canonical cloud partition name to which the region is assigned (e.g. AWS Partitions: aws, aws-cn, aws-us-gov). 27 | - Region (region) [Optional]: The cloud region of the resource. 28 | """ 29 | 30 | cloud_partition: Optional[str] 31 | region: Optional[str] 32 | criticality: Optional[str] 33 | data: Optional[dict[str, object]] 34 | group: Optional[Group] 35 | labels: Optional[list[str]] 36 | name: Optional[str] 37 | namespace: Optional[str] 38 | owner: Optional[User] 39 | type: Optional[str] 40 | uid: Optional[str] 41 | version: Optional[str] 42 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/response_elements.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.objects.container import Container 6 | 7 | 8 | class ResponseElements(BaseModel): 9 | """ 10 | Represents the elements of an API response, particularly useful in containerized applications for capturing the output of containers, the response data, any associated error codes or messages, communication flags, and a descriptive message about the response. 11 | 12 | Attributes: 13 | - Containers (containers) [Optional]: When working with containerized applications, the set of containers which write to the standard the output of a particular logging driver. For example, this may be the set of containers involved in handling api requests and responses for a containerized application. 14 | - Data(data) [Optional]: The additional data that is associated with the api response. 15 | - Error Code (error) [Optional]: Error code associated with the response. 16 | - Error Message (error_message) [Optional]: Descriptive error message. 17 | - Flags (flags) [Optional]: The list of communication flags, normalized to the captions of the flag_ids values. In the case of 'Other', they are defined by the event source. 18 | - Message (message) [Optional]: The description of the event/finding, as defined by the source. 19 | - Response Code (code) [Optional]: The numeric response sent to a request. 20 | 21 | """ 22 | 23 | containers: Optional[list[Container]] 24 | data: Optional[dict[str, object]] 25 | error: Optional[str] 26 | error_message: Optional[str] 27 | flags: Optional[list[str]] 28 | message: Optional[str] 29 | code: Optional[int] 30 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/service.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class Service(BaseModel): 7 | """ 8 | Encapsulates information about a service, including its name, unique identifier, version, and any associated labels. 9 | This model is designed to represent services in a microservices architecture or within any application ecosystem, providing 10 | a way to uniquely identify and describe services. 11 | 12 | Attributes: 13 | - Labels (labels) [Optional]: A list of labels or tags associated with the service, providing additional metadata. 14 | - Name (name) [Optional]: The name of the service, clearly identifying it within the system. 15 | - Unique ID (uid) [Optional]: A unique identifier for the service, ensuring distinct recognition. 16 | - Version (version) [Optional]: The version of the service, helping to track changes or updates over time. 17 | """ 18 | 19 | labels: Optional[list[str]] 20 | name: str 21 | uid: str 22 | version: str 23 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/url.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | 6 | class URL(BaseModel): 7 | """ 8 | The Uniform Resource Locator (URL) object describes the characteristics of a URL. 9 | 10 | Attributes: 11 | """ 12 | 13 | categories: Optional[list[str]] 14 | category_ids: Optional[list[int]] 15 | domain: Optional[str] 16 | hostname: Optional[str] 17 | path: Optional[str] 18 | port: Optional[int] 19 | query_string: Optional[str] 20 | resource_type: Optional[str] 21 | scheme: Optional[str] 22 | subdomain: Optional[str] 23 | url_string: Optional[str] 24 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/user.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.v1 import BaseModel 4 | 5 | from py_ocsf_models.objects.account import Account 6 | from py_ocsf_models.objects.group import Group 7 | from py_ocsf_models.objects.ldap_person import LDAPPerson 8 | from py_ocsf_models.objects.organization import Organization 9 | 10 | 11 | class User(BaseModel): 12 | """ 13 | The User object describes the characteristics of a user/person or a security principal. Defined by D3FEND d3f:UserAccount. 14 | 15 | Attributes: 16 | - Account (account) [Optional]: The user's account or the account associated with the user. 17 | - Alternate ID (uid_alt) [Optional]: The alternate user identifier. For example, the Active Directory user GUID or AWS user Principal ID. 18 | - Domain (domain) [Optional]: The domain where the user is defined. For example: the LDAP or Active Directory domain. 19 | - Email Address (email_addr) [Optional]: The user's primary email address. 20 | - Full Name (full_name) [Optional]: The full name of the person, as per the LDAP Common Name attribute (cn). 21 | - Groups (groups) [Optional]: The administrative groups to which the user belongs. 22 | - LDAP Person (ldap_person) [Optional]: The additional LDAP attributes that describe a person. 23 | - Name (name) [Recommended]: The username. For example, janedoe1. 24 | - Organization (org) [Optional]: Organization and org unit related to the user. 25 | - Type (type) [Optional]: The type of the user. For example, System, AWS IAM User, etc. 26 | - Type ID (type_id) [Recommended]: The account type identifier. 27 | - Unique ID (uid) [Recommended]: The unique user identifier. For example, the Windows user SID, ActiveDirectory DN or AWS user ARN. 28 | - User Credential ID (credential_uid) [Optional]: The unique identifier of the user's credential. For example, AWS Access Key ID. 29 | """ 30 | 31 | account: Account 32 | uid_alt: Optional[str] 33 | domain: Optional[str] 34 | email_addr: Optional[str] 35 | groups: Optional[list[Group]] 36 | ldap_person: Optional[LDAPPerson] 37 | name: str 38 | org: Optional[Organization] 39 | type: Optional[str] 40 | type_id: int 41 | uid: str 42 | credential_uid: Optional[str] 43 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/verdict.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | 4 | class VerdictID(IntEnum): 5 | """ 6 | The normalized verdict (or status) ID of the evidence associated with the security detection. For example, Microsoft Graph Security Alerts contain a verdict enumeration for each type of evidence associated with the Alert. This is typically set by an automated investigation process or an analyst/investigator assigned to the finding. 7 | 0 Unknown: The type is unknown. 8 | 1 False Positive: The verdict for the evidence has been identified as a False Positive. 9 | 2 True Positive: The verdict for the evidence has been identified as a True Positive. 10 | 3 Disregard: The verdict for the evidence is that is should be Disregarded. 11 | 4 Suspicious: The verdict for the evidence is that the behavior has been identified as Suspicious. 12 | 5 Benign: The verdict for the evidence is that the behavior has been identified as Benign. 13 | 6 Test: The evidence is part of a Test, or other sanctioned behavior(s). 14 | 7 Insufficient Data: There is insufficient data to render a verdict on the evidence. 15 | 8 Security Risk: The verdict for the evidence is that the behavior has been identified as a Security Risk. 16 | 9 Managed Externally: The verdict for the evidence is Managed Externally, such as in a case management tool. 17 | 10 Duplicate: This evidence duplicates existing evidence related to this finding. 18 | 99 Other: The type is not mapped. See the type attribute, which contains a data source specific value. 19 | """ 20 | 21 | Unknown = 0 22 | FalsePositive = 1 23 | TruePositive = 2 24 | Disregard = 3 25 | Suspicious = 4 26 | Benign = 5 27 | Test = 6 28 | InsufficientData = 7 29 | SecurityRisk = 8 30 | ManagedExternally = 9 31 | Duplicate = 10 32 | Other = 99 33 | -------------------------------------------------------------------------------- /py_ocsf_models/objects/vulnerability_details.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import List, Optional 3 | 4 | from pydantic.v1 import BaseModel 5 | 6 | from py_ocsf_models.objects.affected_software_package import AffectedSoftwarePackage 7 | from py_ocsf_models.objects.cve import CVE 8 | from py_ocsf_models.objects.cwe import CWE 9 | from py_ocsf_models.objects.remediation import Remediation 10 | 11 | 12 | class VulnerabilityDetails(BaseModel): 13 | """ 14 | The vulnerability is an unintended characteristic of a computing component or system configuration that multiplies the risk of an adverse event or a loss occurring either due to accidental exposure, deliberate attack, or conflict with new system components. 15 | 16 | Attributes: 17 | - Affected Code (affected_code) [Optional]: List of AffectedCode objects that describe details about code blocks identified as vulnerable. 18 | - Affected Software Packages (affected_packages) [Optional]: List of software packages identified as affected by a vulnerability/vulnerabilities. 19 | - CVE (cve) [Recommended]: The Common Vulnerabilities and Exposures (CVE). 20 | - CWE (cwe) [Recommended]: The CWE object represents a weakness in a software system that can be exploited by a threat actor to perform an attack. 21 | - Description (desc) [Optional]: The description of the vulnerability. 22 | - Exploit Availability (is_exploit_available) [Optional]: Indicates if an exploit or a PoC (proof-of-concept) is available for the reported vulnerability. 23 | - First Seen (first_seen_time) [Optional]: The time when the vulnerability was first observed. 24 | - First Seen (first_seen_time_dt) [Optional]: The time when the vulnerability was first observed in datetime format. 25 | - Knowledgebase Articles (kb_article_list) [Optional]: A list of KB articles or patches related to an endpoint. A KB Article contains metadata that describes the patch or an update. 26 | - Last Seen (last_seen_time) [Optional]: The time when the vulnerability was most recently observed. 27 | - Last Seen (last_seen_time_dt) [Optional]: The time when the vulnerability was most recently observed in datetime format. 28 | - References (references) [Recommended]: A list of reference URLs with additional information about the vulnerability. 29 | - Related Vulnerabilities (related_vulnerabilities) [Optional]: List of vulnerabilities that are related to this vulnerability. 30 | - Remediation Guidance (remediation) [Optional]: The remediation recommendations on how to mitigate the identified vulnerability. 31 | - Severity (severity) [Optional]: The vendor assigned severity of the vulnerability. 32 | - Title (title) [Optional]: A title or a brief phrase summarizing the discovered vulnerability. 33 | - Vendor Name (vendor_name) [Optional]: The name of the vendor that identified the vulnerability. 34 | 35 | Just one of these mutually exclusive attributes must be present: advisory, cve, cwe 36 | 37 | """ 38 | 39 | # TODO 40 | # advisory: Optional[Advisory] 41 | # affected_code: Optional[List[AffectedCode]] 42 | affected_packages: Optional[List[AffectedSoftwarePackage]] 43 | cve: Optional[CVE] 44 | cwe: Optional[CWE] 45 | desc: Optional[str] 46 | is_exploit_available: Optional[bool] 47 | first_seen_time: Optional[int] 48 | first_seen_time_dt: Optional[datetime] 49 | last_seen_time: Optional[int] 50 | last_seen_time_dt: Optional[datetime] 51 | references: Optional[List[str]] 52 | related_vulnerabilities: Optional[List[str]] 53 | remediation: Optional[Remediation] 54 | severity: Optional[str] 55 | title: Optional[str] 56 | vendor_name: Optional[str] 57 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | build-backend = "poetry.core.masonry.api" 3 | requires = ["poetry-core>=2.0"] 4 | 5 | # https://peps.python.org/pep-0621/ 6 | [project] 7 | authors = [{name = "Prowler Engineering", email = "engineering@prowler.com"}] 8 | classifiers = [ 9 | "Programming Language :: Python :: 3", 10 | "License :: OSI Approved :: Apache Software License" 11 | ] 12 | dependencies = [ 13 | "cryptography==44.0.1", 14 | "email-validator==2.2.0", 15 | "pydantic (>=2.9.2,<3.0.0)" 16 | ] 17 | description = "This is a Python implementation of the OCSF models. The models are used to represent the data of the OCSF Schema defined in https://schema.ocsf.io/." 18 | license = "Apache-2.0" 19 | name = "py-ocsf-models" 20 | packages = [ 21 | {include = "py_ocsf_models"} 22 | ] 23 | readme = "README.md" 24 | requires-python = ">3.9.1,<3.14" 25 | version = "0.7.1" 26 | 27 | [project.urls] 28 | "Changelog" = "https://github.com/prowler-cloud/py-ocsf-models/releases" 29 | "Documentation" = "https://docs.prowler.cloud" 30 | "Homepage" = "https://github.com/prowler-cloud/py-ocsf-models" 31 | "Issue tracker" = "https://github.com/prowler-cloud/py-ocsf-models/issues" 32 | 33 | [tool.mypy] 34 | allow_redefinition = true 35 | files = ["./py_ocsf_models"] 36 | strict = true 37 | 38 | [tool.poetry.group.dev.dependencies] 39 | bandit = "1.8.5" 40 | black = "25.1.0" 41 | flake8 = "7.1.2" 42 | mypy = "1.16.1" 43 | pylint = "3.3.7" 44 | pytest = "8.3.5" 45 | pytest-cov = "6.0.0" 46 | pytest-env = "1.1.5" 47 | pytest-randomly = "3.16.0" 48 | pytest-xdist = "3.8.0" 49 | requests = "^2.32.4" 50 | ruff = "0.12.1" 51 | safety = "3.2.14" 52 | vulture = "2.14" 53 | 54 | [tool.poetry-version-plugin] 55 | source = "init" 56 | -------------------------------------------------------------------------------- /tests/application_security_posture_finding_test.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | import requests 4 | 5 | from py_ocsf_models import OCSF_VERSION 6 | from py_ocsf_models.events.findings.activity_id import ActivityID 7 | from py_ocsf_models.events.findings.application_security_posture_finding import ( 8 | ApplicationSecurityPostureFinding, 9 | ApplicationSecurityPostureFindingTypeID, 10 | ) 11 | from py_ocsf_models.events.findings.category_uid import CategoryUID 12 | from py_ocsf_models.events.findings.class_uid import ClassUID 13 | from py_ocsf_models.events.findings.severity_id import SeverityID 14 | from py_ocsf_models.objects.affected_software_package import ( 15 | AffectedSoftwarePackage, 16 | SoftwarePackageTypeID, 17 | ) 18 | from py_ocsf_models.objects.cve import CVE 19 | from py_ocsf_models.objects.cvss import CVSSScore 20 | from py_ocsf_models.objects.epss import EPSS 21 | from py_ocsf_models.objects.finding_info import FindingInformation 22 | from py_ocsf_models.objects.fingerprint import AlgorithmID, FingerPrint 23 | from py_ocsf_models.objects.metadata import Metadata 24 | from py_ocsf_models.objects.metric import Metric 25 | from py_ocsf_models.objects.product import Feature, Product 26 | from py_ocsf_models.objects.remediation import Remediation 27 | from py_ocsf_models.objects.resource_details import ResourceDetails 28 | from py_ocsf_models.objects.vulnerability_details import VulnerabilityDetails 29 | 30 | 31 | class TestApplicationSecurityPostureFinding: 32 | def test_application_security_posture_finding(self) -> None: 33 | """ 34 | Tests the creation and validation of an ApplicationSecurityPostureFinding OCSF event. 35 | This test populates an ApplicationSecurityPostureFinding object with 36 | sample data covering SAST, SCA, DAST, IaC, and Secret findings, 37 | and then validates it against the OCSF schema validator. 38 | """ 39 | app_sec_finding = ApplicationSecurityPostureFinding( 40 | activity_id=ActivityID.Update.value, 41 | class_uid=ClassUID.ApplicationSecurityPostureFinding.value, 42 | category_uid=CategoryUID.Findings.value, 43 | metadata=Metadata( 44 | version=OCSF_VERSION, 45 | product=Product( 46 | feature=Feature( 47 | name="AppScan", uid="appscan-feat-1", version="1.0" 48 | ), 49 | lang="en", 50 | name="Application Security Scanner", 51 | path="Path/to/scanner", 52 | cpe_name="cpe:/a:ibm:appscan:1.0", 53 | url_string="https://www.ibm.com/appscan", 54 | uid="appscan-prod-1", 55 | vendor_name="IBM", 56 | version="1.0", 57 | ), 58 | profiles=["datetime"], 59 | ), 60 | vulnerabilities=[ 61 | VulnerabilityDetails( 62 | cve=CVE( 63 | uid="CVE-2021-44228", 64 | desc="Apache Log4j2 JNDI Remote Code Execution", 65 | cvss=[ 66 | CVSSScore( 67 | base_score=10.0, 68 | version="3.1", 69 | vector_string="CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", 70 | metrics=[ 71 | Metric(name="privilegesRequired", value="NONE") 72 | ], 73 | ) 74 | ], 75 | references=["https://nvd.nist.gov/vuln/detail/CVE-2021-44228"], 76 | epss=EPSS(score="0.975620000", percentile="0.999980000"), 77 | ), 78 | # cwe=CWE( 79 | # uid="CWE-079", 80 | # caption="Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')", 81 | # src_url=URL( 82 | # url_string="https://cwe.mitre.org/data/definitions/79.html" 83 | # ), 84 | # ), 85 | desc="A critical vulnerability in Log4j2 allowing remote code execution.", 86 | remediation=Remediation( 87 | desc="Upgrade Log4j2 to version 2.17.1 or later.", 88 | ), 89 | severity=SeverityID.Critical.name, 90 | title="vuln-log4shell-001", 91 | affected_packages=[ 92 | AffectedSoftwarePackage( 93 | architecture="Architecture", 94 | cpe_name="CPE Name", 95 | epoch=1, 96 | fixed_in_version="1.2.3", 97 | hash=FingerPrint( 98 | algorithm_id=1, 99 | algorithm="MD5", 100 | value="d73b04b0e696b0945283defa3eee4538", 101 | ), 102 | license="GPL v3.0", 103 | license_url="https://www.gnu.org/licenses/gpl-3.0.en.html", 104 | name="Package Name", 105 | package_manager="npm", 106 | package_manager_url="https://something/npm/Package Name", 107 | path="/path/to/install/", 108 | purl="PURL", 109 | release="rc1", 110 | remediation=Remediation(desc="remediation"), 111 | src_url="https://example.com/sources", 112 | type="Application", 113 | type_id=1, 114 | uid="Package Name-1.2.2-rc1", 115 | vendor_name="Vendor Name", 116 | version="1.2.3", 117 | ), 118 | ], 119 | ) 120 | ], 121 | resources=[ 122 | ResourceDetails( 123 | name="my-web-application", 124 | namespace="prod", 125 | uid="app-12345", 126 | type="Application", 127 | criticality="High", 128 | ) 129 | ], 130 | finding_info=FindingInformation( 131 | title="Critical Application Security Posture Findings Detected", 132 | desc=( 133 | "Multiple critical and high severity vulnerabilities detected across " 134 | "SAST, SCA, DAST, IaC, and Secret scanning for the application." 135 | ), 136 | uid="app-sec-finding-001", 137 | ), 138 | severity_id=SeverityID.Critical.value, 139 | time=int(datetime.now().timestamp()), 140 | time_dt=datetime.now(), 141 | timezone_offset=0, 142 | type_uid=ApplicationSecurityPostureFindingTypeID.Update, 143 | ) 144 | 145 | # Assertions to validate the populated object 146 | assert app_sec_finding.severity_id == SeverityID.Critical.value 147 | assert ( 148 | app_sec_finding.class_uid 149 | == ClassUID.ApplicationSecurityPostureFinding.value 150 | ) 151 | assert app_sec_finding.category_name == CategoryUID.Findings.name 152 | assert app_sec_finding.category_uid == CategoryUID.Findings.value 153 | assert app_sec_finding.activity_id == ActivityID.Update.value 154 | 155 | # Vulnerability assertions 156 | vulnerability = app_sec_finding.vulnerabilities[0] 157 | assert vulnerability.cve.uid == "CVE-2021-44228" 158 | assert vulnerability.cve.cvss[0].base_score == 10.0 159 | assert vulnerability.cve.cvss[0].version == "3.1" 160 | assert ( 161 | vulnerability.cve.cvss[0].vector_string 162 | == "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H" 163 | ) 164 | assert vulnerability.cve.cvss[0].metrics[0].name == "privilegesRequired" 165 | assert vulnerability.cve.cvss[0].metrics[0].value == "NONE" 166 | assert vulnerability.cve.references == [ 167 | "https://nvd.nist.gov/vuln/detail/CVE-2021-44228" 168 | ] 169 | assert vulnerability.cve.epss.score == "0.975620000" 170 | assert vulnerability.cve.epss.percentile == 0.99998 171 | # assert vulnerability.cwe.uid == "CWE-079" 172 | assert vulnerability.severity == SeverityID.Critical.name 173 | assert vulnerability.title == "vuln-log4shell-001" 174 | assert vulnerability.remediation 175 | assert vulnerability.affected_packages[0].architecture == "Architecture" 176 | assert vulnerability.affected_packages[0].cpe_name == "CPE Name" 177 | assert vulnerability.affected_packages[0].epoch == 1 178 | assert vulnerability.affected_packages[0].fixed_in_version == "1.2.3" 179 | assert vulnerability.affected_packages[0].hash.algorithm_id == AlgorithmID.MD5 180 | assert vulnerability.affected_packages[0].hash.algorithm == AlgorithmID.MD5.name 181 | assert ( 182 | vulnerability.affected_packages[0].hash.value 183 | == "d73b04b0e696b0945283defa3eee4538" 184 | ) 185 | assert vulnerability.affected_packages[0].license == "GPL v3.0" 186 | assert ( 187 | vulnerability.affected_packages[0].license_url 188 | == "https://www.gnu.org/licenses/gpl-3.0.en.html" 189 | ) 190 | assert vulnerability.affected_packages[0].name == "Package Name" 191 | assert vulnerability.affected_packages[0].package_manager == "npm" 192 | assert ( 193 | vulnerability.affected_packages[0].package_manager_url 194 | == "https://something/npm/Package Name" 195 | ) 196 | assert vulnerability.affected_packages[0].path == "/path/to/install/" 197 | assert vulnerability.affected_packages[0].purl == "PURL" 198 | assert vulnerability.affected_packages[0].release == "rc1" 199 | assert vulnerability.affected_packages[0].remediation.desc == "remediation" 200 | assert ( 201 | vulnerability.affected_packages[0].src_url == "https://example.com/sources" 202 | ) 203 | assert ( 204 | vulnerability.affected_packages[0].type 205 | == SoftwarePackageTypeID.Application.name 206 | ) 207 | assert ( 208 | vulnerability.affected_packages[0].type_id 209 | == SoftwarePackageTypeID.Application 210 | ) 211 | assert vulnerability.affected_packages[0].uid == "Package Name-1.2.2-rc1" 212 | assert vulnerability.affected_packages[0].vendor_name == "Vendor Name" 213 | assert vulnerability.affected_packages[0].version == "1.2.3" 214 | 215 | # Finding Info assertions 216 | assert ( 217 | app_sec_finding.finding_info.title 218 | == "Critical Application Security Posture Findings Detected" 219 | ) 220 | 221 | assert app_sec_finding.finding_info.uid == "app-sec-finding-001" 222 | 223 | # Resources details 224 | resource = app_sec_finding.resources[0] 225 | assert resource.criticality == "High" 226 | assert resource.type == "Application" 227 | assert resource.name == "my-web-application" 228 | assert resource.namespace == "prod" 229 | assert resource.uid == "app-12345" 230 | 231 | # Convert to JSON and validate against OCSF schema 232 | app_sec_finding_json = app_sec_finding.json(exclude_unset=True) 233 | url = "https://schema.ocsf.io/api/v2/validate" 234 | headers = {"content-type": "application/json"} 235 | 236 | response = requests.post(url, headers=headers, data=app_sec_finding_json) 237 | assert response.status_code == 200, f"Schema validation failed: {response.text}" 238 | assert response.json()["error_count"] == 0 239 | -------------------------------------------------------------------------------- /tests/compliance_finding_test.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | import requests 4 | 5 | from py_ocsf_models import OCSF_VERSION 6 | from py_ocsf_models.events.findings.activity_id import ActivityID 7 | from py_ocsf_models.events.findings.category_uid import CategoryUID 8 | from py_ocsf_models.events.findings.class_uid import ClassUID 9 | from py_ocsf_models.events.findings.compliance_finding import ( 10 | ComplianceFinding, 11 | ComplianceFindingTypeID, 12 | ) 13 | from py_ocsf_models.events.findings.severity_id import SeverityID 14 | from py_ocsf_models.objects.assessment import Assessment 15 | from py_ocsf_models.objects.check import Check 16 | from py_ocsf_models.objects.compliance import Compliance 17 | from py_ocsf_models.objects.compliance_status import StatusID as ComplianceStatusID 18 | from py_ocsf_models.objects.evidence_artifacts import EvidenceArtifacts 19 | from py_ocsf_models.objects.finding_info import FindingInformation 20 | from py_ocsf_models.objects.metadata import Metadata 21 | from py_ocsf_models.objects.product import Feature, Product 22 | from py_ocsf_models.objects.resource_details import ResourceDetails 23 | from py_ocsf_models.objects.url import URL 24 | from py_ocsf_models.objects.verdict import VerdictID 25 | 26 | 27 | class TestComplianceFinding: 28 | def test_compliance_finding(self): 29 | compliance_finding = ComplianceFinding( 30 | activity_id=ActivityID.Create.value, 31 | category_uid=CategoryUID.Findings.value, 32 | class_uid=ClassUID.ComplianceFinding.value, 33 | metadata=Metadata( 34 | version=OCSF_VERSION, 35 | product=Product( 36 | feature=Feature(name="Name", uid="123", version="Version"), 37 | lang="en", 38 | name="Name", 39 | path="Path", 40 | cpe_name="CPE Name", 41 | url_string="https://www.example.com", 42 | uid="123", 43 | vendor_name="Vendor Name", 44 | version="Version", 45 | ), 46 | profiles=["datetime"], 47 | ), 48 | compliance=Compliance( 49 | assessments=[ 50 | Assessment( 51 | category="Access Control", 52 | name="github authn configuration", 53 | desc=( 54 | "This assessment checks that the repository being " 55 | "assessed is hosted on GitHub" 56 | ), 57 | uid="123", 58 | meets_criteria=True, 59 | ) 60 | ], 61 | category="Supply Chain Risk Assessment", 62 | checks=[ 63 | Check( 64 | name=( 65 | "OSPS-AC-01.01: When a user attempts to access a sensitive " 66 | "resource in the project's version control system, the " 67 | "system MUST require the user to complete a multi-factor " 68 | "authentication process." 69 | ), 70 | uid="OSPS-AC-01.01", 71 | version="2025-02-25", 72 | severity_id=SeverityID.Critical.value, 73 | standards=["Open Source Project Security Baseline v2025-02-25"], 74 | status="Pass", 75 | status_id=ComplianceStatusID.Pass.value, 76 | ) 77 | ], 78 | control="OSPS-AC-01", 79 | desc=( 80 | "Enforce multi-factor authentication for the project's " 81 | "version control system, requiring collaborators to provide " 82 | "a second form of authentication when accessing sensitive " 83 | "data or modifying repository settings. Passkeys are " 84 | "acceptable for this control." 85 | ), 86 | requirements=[ 87 | "https://baseline.openssf.org/versions/2025-02-25#osps-ac-0101" 88 | ], 89 | standards=["Open Source Project Security Baseline v2025-02-25"], 90 | status_id=ComplianceStatusID.Pass.value, 91 | ), 92 | evidences=[ 93 | EvidenceArtifacts( 94 | name="GitHub required and default configuration", 95 | resources=[ 96 | ResourceDetails( 97 | name="security-baseline", 98 | namespace="ossf", 99 | uid="https://github.com/ossf/security-baseline", 100 | type="GitHub", 101 | criticality="Critical", 102 | hostname="https://github.com/ossf/security-baseline", 103 | ) 104 | ], 105 | url=URL( 106 | url_string="https://github.com/ossf/security-baseline", 107 | ), 108 | verdict_id=VerdictID.Benign.value, 109 | ) 110 | ], 111 | finding_info=FindingInformation( 112 | title=( 113 | "Repository is hosted on GitHub and subject to required and " 114 | "default configured MFA authentication" 115 | ), 116 | desc=( 117 | "The repository is verified as hosted on GitHub and adheres " 118 | "to GitHub's authentication policies for MFA. See " 119 | "https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/about-mandatory-two-factor-authentication" 120 | ), 121 | uid="123", 122 | ), 123 | severity_id=SeverityID.Critical.value, 124 | time=int(datetime.now().timestamp()), 125 | time_dt=datetime.now(), 126 | timezone_offset=0, 127 | type_uid=ComplianceFindingTypeID.Create, 128 | ) 129 | 130 | assert compliance_finding.severity_id == SeverityID.Critical.value 131 | 132 | assert compliance_finding.compliance.checks[0].uid == "OSPS-AC-01.01" 133 | assert compliance_finding.compliance.checks[0].standards == [ 134 | "Open Source Project Security Baseline v2025-02-25" 135 | ] 136 | 137 | check = compliance_finding.compliance.checks[0] 138 | assert check.status == "Pass" 139 | assert check.status_id == ComplianceStatusID.Pass.value 140 | 141 | evidence = compliance_finding.evidences[0] 142 | assert evidence.name == "GitHub required and default configuration" 143 | assert evidence.resources[0].name == "security-baseline" 144 | 145 | title = compliance_finding.finding_info.title 146 | expected_title = ( 147 | "Repository is hosted on GitHub and subject to required and " 148 | "default configured MFA authentication" 149 | ) 150 | assert title == expected_title 151 | desc = compliance_finding.finding_info.desc 152 | expected_desc = ( 153 | "The repository is verified as hosted on GitHub and adheres " 154 | "to GitHub's authentication policies for MFA. See " 155 | "https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/about-mandatory-two-factor-authentication" 156 | ) 157 | assert desc == expected_desc 158 | uid = compliance_finding.finding_info.uid 159 | assert uid == "123" 160 | 161 | compliance_finding_json = compliance_finding.json(exclude_unset=True) 162 | url = "https://schema.ocsf.io/api/v2/validate" 163 | headers = {"content-type": "application/json"} 164 | 165 | response = requests.post(url, headers=headers, data=compliance_finding_json) 166 | assert response.status_code == 200, f"Schema validation failed: {response.text}" 167 | assert response.json()["error_count"] == 0 168 | -------------------------------------------------------------------------------- /tests/detection_finding_test.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | from datetime import datetime 3 | 4 | import requests 5 | 6 | from py_ocsf_models import OCSF_VERSION 7 | from py_ocsf_models.events.findings.activity_id import ActivityID 8 | from py_ocsf_models.events.findings.category_uid import CategoryUID 9 | from py_ocsf_models.events.findings.confidence_id import ConfidenceID 10 | from py_ocsf_models.events.findings.detection_finding import DetectionFinding 11 | from py_ocsf_models.events.findings.detection_finding_type_id import ( 12 | DetectionFindingTypeID, 13 | ) 14 | from py_ocsf_models.events.findings.finding import FindingInformation 15 | from py_ocsf_models.events.findings.severity_id import SeverityID 16 | from py_ocsf_models.events.findings.status_id import StatusID 17 | from py_ocsf_models.objects.api import ( 18 | API, 19 | Group, 20 | RequestElements, 21 | ResponseElements, 22 | Service, 23 | ) 24 | from py_ocsf_models.objects.cloud import Account, Cloud, Organization 25 | from py_ocsf_models.objects.container import Container, FingerPrint, Image 26 | from py_ocsf_models.objects.cve import CVE 27 | from py_ocsf_models.objects.dns_query import DNSOpcodeID, DNSQuery 28 | from py_ocsf_models.objects.evidence_artifacts import EvidenceArtifacts 29 | from py_ocsf_models.objects.metadata import Metadata 30 | from py_ocsf_models.objects.operating_system import OperatingSystem, TypeID 31 | from py_ocsf_models.objects.product import Feature, Product 32 | from py_ocsf_models.objects.remediation import KBArticle, Remediation 33 | from py_ocsf_models.objects.resource_details import ResourceDetails 34 | from py_ocsf_models.objects.vulnerability_details import VulnerabilityDetails 35 | 36 | PROWLER_VERSION = "4.1.0" 37 | PROWLER_PRODUCT = "Prowler" 38 | 39 | 40 | class TestDetectionFinding: 41 | def test_detection_finding(self): 42 | pod_uuid = str(uuid.uuid4()) 43 | detection_finding = DetectionFinding( 44 | status=StatusID.New.name, 45 | status_id=StatusID.New.value, 46 | metadata=Metadata( 47 | version=OCSF_VERSION, 48 | product=Product( 49 | feature=Feature( 50 | name=PROWLER_PRODUCT, uid="123", version=PROWLER_VERSION 51 | ), 52 | lang="en", 53 | name=PROWLER_PRODUCT, 54 | path="Path", 55 | cpe_name="CPE Name", 56 | url_string="https://www.example.com", 57 | uid="123", 58 | vendor_name=PROWLER_PRODUCT, 59 | version=PROWLER_VERSION, 60 | ), 61 | profiles=["cloud", "datetime"], 62 | ), 63 | finding_info=FindingInformation( 64 | title="Title", 65 | uid="123", 66 | created_time=int(datetime.now().timestamp()), 67 | created_time_dt=datetime.now(), 68 | ), 69 | severity_id=SeverityID.Informational, 70 | severity=SeverityID(1).name, 71 | activity_name="Create", 72 | activity_id=1, 73 | comment="Comment", 74 | confidence="Low", 75 | confidence_id=1, 76 | confidence_score=123, 77 | end_time=int(datetime.now().timestamp()), 78 | end_time_dt=datetime.now(), 79 | start_time=int(datetime.now().timestamp()), 80 | start_time_dt=datetime.now(), 81 | resources=[ 82 | ResourceDetails( 83 | id="123", 84 | name="Resource 1", 85 | type="Resource", 86 | details="Details of the resource", 87 | cloud_partition="aws", 88 | ) 89 | ], 90 | category_name=CategoryUID.Findings.name, 91 | category_uid=CategoryUID.Findings.value, 92 | class_name="Detection Finding", 93 | class_uid=2004, 94 | api=API( 95 | request=RequestElements( 96 | containers=[ 97 | Container( 98 | hash=FingerPrint( 99 | algorithm="SHA-256", 100 | algorithm_id=3, 101 | value="123", 102 | ), 103 | image=Image( 104 | name="Image 1", 105 | labels=["Label 1"], 106 | path="Path 1", 107 | uid="123", 108 | ), 109 | name="Container 1", 110 | network_driver="Network Driver 1", 111 | orchestrator="Orchestrator 1", 112 | pod_uuid=pod_uuid, 113 | runtime="Runtime 1", 114 | size=123, 115 | uid="123", 116 | ) 117 | ], 118 | data={"key": "value"}, 119 | flags=["Flag 1"], 120 | uid="123", 121 | ), 122 | response=ResponseElements( 123 | containers=[ 124 | Container( 125 | hash=FingerPrint( 126 | algorithm="SHA-256", 127 | algorithm_id=3, 128 | value="123", 129 | ), 130 | image=Image( 131 | name="Image 1", 132 | labels=["Label 1"], 133 | path="Path 1", 134 | uid="123", 135 | ), 136 | name="Container 1", 137 | network_driver="Network Driver 1", 138 | orchestrator="Orchestrator 1", 139 | pod_uuid=pod_uuid, 140 | runtime="Runtime 1", 141 | size=123, 142 | uid="123", 143 | ) 144 | ], 145 | data={"key": "value"}, 146 | error="Error", 147 | error_message="Error Message", 148 | flags=["Flag 1"], 149 | message="Message", 150 | code=123, 151 | ), 152 | group=Group( 153 | type="Group", 154 | desc="Details of the group", 155 | domain="Domain 1", 156 | name="Group 1", 157 | privileges=["Privilege 1"], 158 | uid="123", 159 | ), 160 | operation="GET", 161 | service=Service( 162 | labels=["Label 1"], 163 | name="Service 1", 164 | uid="123", 165 | version="1.0", 166 | ), 167 | version="1.0", 168 | ), 169 | cloud=Cloud( 170 | account=Account( 171 | name="Account 1", 172 | type="AWS IAM User", 173 | type_id="3", 174 | uid="123", 175 | labels=["label 1"], 176 | ), 177 | zone="Zone 1", 178 | org=Organization( 179 | name="Organization 1", ou_uid="123", ou_name="OU 1", uid="123" 180 | ), 181 | provider="Provider 1", 182 | region="Region 1", 183 | ), 184 | container=Container( 185 | hash=FingerPrint( 186 | algorithm="SHA-256", 187 | algorithm_id=3, 188 | value="123", 189 | ), 190 | image=Image( 191 | name="Image 1", 192 | labels=["Label 1"], 193 | path="Path 1", 194 | uid="123", 195 | ), 196 | name="Container 1", 197 | network_driver="Network Driver 1", 198 | orchestrator="Orchestrator 1", 199 | pod_uuid=pod_uuid, 200 | runtime="Runtime 1", 201 | size=123, 202 | uid="123", 203 | ), 204 | count=123, 205 | duration=123, 206 | time=int(datetime.now().timestamp()), 207 | time_dt=datetime.now(), 208 | evidences=[ 209 | EvidenceArtifacts( 210 | api=API( 211 | request=RequestElements( 212 | containers=[ 213 | Container( 214 | hash=FingerPrint( 215 | algorithm="SHA-256", 216 | algorithm_id=3, 217 | value="123", 218 | ), 219 | image=Image( 220 | name="Image 1", 221 | labels=["Label 1"], 222 | path="Path 1", 223 | uid="123", 224 | ), 225 | name="Container 1", 226 | network_driver="Network Driver 1", 227 | orchestrator="Orchestrator 1", 228 | pod_uuid=pod_uuid, 229 | runtime="Runtime 1", 230 | size=123, 231 | uid="123", 232 | ) 233 | ], 234 | data={"key": "value"}, 235 | flags=["Flag 1"], 236 | uid="123", 237 | ), 238 | response=ResponseElements( 239 | containers=[ 240 | Container( 241 | hash=FingerPrint( 242 | algorithm="SHA-256", 243 | algorithm_id=3, 244 | value="123", 245 | ), 246 | image=Image( 247 | name="Image 1", 248 | labels=["Label 1"], 249 | path="Path 1", 250 | uid="123", 251 | ), 252 | name="Container 1", 253 | network_driver="Network Driver 1", 254 | orchestrator="Orchestrator 1", 255 | pod_uuid=pod_uuid, 256 | runtime="Runtime 1", 257 | size=123, 258 | uid="123", 259 | ) 260 | ], 261 | data={"key": "value"}, 262 | error="Error", 263 | error_message="Error Message", 264 | flags=["Flag 1"], 265 | message="Message", 266 | code=123, 267 | ), 268 | group=Group( 269 | type="Group", 270 | desc="Details of the group", 271 | domain="Domain 1", 272 | name="Group 1", 273 | privileges=["Privilege 1"], 274 | uid="123", 275 | ), 276 | operation="GET", 277 | service=Service( 278 | labels=["Label 1"], 279 | name="Service 1", 280 | uid="123", 281 | version="1.0", 282 | ), 283 | version="1.0", 284 | ), 285 | query=DNSQuery( 286 | opcode="Query", 287 | opcode_id=DNSOpcodeID.Query, 288 | hostname="www.example.com", 289 | packet_uid=123, 290 | class_="IN", 291 | type="A", 292 | ), 293 | data={"key": "value"}, 294 | ) 295 | ], 296 | impact="Low", 297 | impact_score=123, 298 | impact_id=1, 299 | remediation=Remediation( 300 | desc="Description", 301 | kb_article_list=[ 302 | KBArticle( 303 | classification="Classification", 304 | created_time=int(datetime.now().timestamp()), 305 | os=OperatingSystem( 306 | cpu_bits=64, 307 | country="US", 308 | lang="en", 309 | name="Name", 310 | build="Build", 311 | edition="Edition", 312 | sp_name="SP Name", 313 | sp_ver=123, 314 | cpe_name="CPE Name", 315 | type="Windows", 316 | type_id=100, 317 | version="Version", 318 | ), 319 | bulletin="Bulletin", 320 | product=Product( 321 | feature=Feature(name="Name", uid="123", version="Version"), 322 | lang="en", 323 | name="Name", 324 | path="Path", 325 | cpe_name="CPE Name", 326 | url_string="https://www.example.com", 327 | uid="123", 328 | vendor_name="Vendor Name", 329 | version="Version", 330 | ), 331 | severity="Severity", 332 | size=123, 333 | src_url="https://www.example.com", 334 | is_superseded=True, 335 | title="Title", 336 | uid="123", 337 | ) 338 | ], 339 | references=["https://www.example.com"], 340 | ), 341 | risk_level="Low", 342 | risk_level_id=1, 343 | risk_score=123, 344 | risk_details="Risk Details", 345 | timezone_offset=123, 346 | type_uid=DetectionFindingTypeID.Create, 347 | type_name=f"Detection Finding: {DetectionFindingTypeID.Create.name}", 348 | vulnerabilities=[ 349 | VulnerabilityDetails( 350 | desc="Description", 351 | cve=CVE( 352 | uid="CVE-2021-1234", 353 | ), 354 | is_exploit_available=True, 355 | first_seen_time=int(datetime.now().timestamp()), 356 | first_seen_time_dt=datetime.now(), 357 | last_seen_time=int(datetime.now().timestamp()), 358 | last_seen_time_dt=datetime.now(), 359 | references=["https://www.example.com"], 360 | related_vulnerabilities=["123"], 361 | remediation=Remediation( 362 | desc="Description", 363 | kb_article_list=[ 364 | KBArticle( 365 | classification="Classification", 366 | created_time=int(datetime.now().timestamp()), 367 | created_time_dt=datetime.now(), 368 | os=OperatingSystem( 369 | cpu_bits=64, 370 | country="US", 371 | lang="en", 372 | name="Name", 373 | build="Build", 374 | edition="Edition", 375 | sp_name="SP Name", 376 | sp_ver=123, 377 | cpe_name="CPE Name", 378 | type="Windows", 379 | type_id=100, 380 | version="Version", 381 | ), 382 | bulletin="Bulletin", 383 | product=Product( 384 | feature=Feature( 385 | name="Name", uid="123", version="Version" 386 | ), 387 | lang="en", 388 | name="Name", 389 | path="Path", 390 | cpe_name="CPE Name", 391 | url_string="https://www.example.com", 392 | uid="123", 393 | vendor_name="Vendor Name", 394 | version="Version", 395 | ), 396 | severity="Severity", 397 | size=123, 398 | src_url="https://www.example.com", 399 | is_superseded=True, 400 | title="Title", 401 | uid="123", 402 | ) 403 | ], 404 | references=["https://www.example.com"], 405 | ), 406 | severity="Severity", 407 | title="Title", 408 | vendor_name="Vendor Name", 409 | ) 410 | ], 411 | ) 412 | 413 | # Assert Severity 414 | assert detection_finding.severity == "Informational" 415 | assert detection_finding.severity_id == SeverityID.Informational 416 | 417 | # Assert Metadata and Product 418 | assert detection_finding.metadata.version == OCSF_VERSION 419 | product = detection_finding.metadata.product 420 | assert product.feature.name == PROWLER_PRODUCT 421 | assert product.feature.uid == "123" 422 | assert product.feature.version == PROWLER_VERSION 423 | assert product.lang == "en" 424 | assert product.name == PROWLER_PRODUCT 425 | assert product.path == "Path" 426 | assert product.cpe_name == "CPE Name" 427 | assert product.url_string == "https://www.example.com" 428 | assert product.uid == "123" 429 | assert product.vendor_name == PROWLER_PRODUCT 430 | assert product.version == PROWLER_VERSION 431 | 432 | # Assert FindingInformation 433 | assert detection_finding.finding_info.title == "Title" 434 | assert detection_finding.finding_info.uid == "123" 435 | 436 | # Assert simple attributes 437 | assert detection_finding.severity_id == SeverityID.Informational 438 | assert detection_finding.activity_name == "Create" 439 | assert detection_finding.activity_id == ActivityID.Create 440 | assert detection_finding.comment == "Comment" 441 | assert detection_finding.confidence == "Low" 442 | assert detection_finding.confidence_id == ConfidenceID.Low 443 | assert detection_finding.confidence_score == 123 444 | 445 | # Assert ResourceDetails 446 | resource = detection_finding.resources[0] 447 | assert resource.name == "Resource 1" 448 | assert resource.type == "Resource" 449 | 450 | # Assert Cloud profile and nested objects 451 | assert detection_finding.api.operation == "GET" 452 | assert detection_finding.api.version == "1.0" 453 | assert detection_finding.api.service.name == "Service 1" 454 | 455 | assert detection_finding.cloud.account.name == "Account 1" 456 | assert detection_finding.cloud.zone == "Zone 1" 457 | assert detection_finding.cloud.org.name == "Organization 1" 458 | assert detection_finding.cloud.provider == "Provider 1" 459 | assert detection_finding.cloud.region == "Region 1" 460 | assert detection_finding.cloud.account.labels == ["label 1"] 461 | 462 | # Assert DNSQuery 463 | dns_query = detection_finding.evidences[0].query 464 | assert dns_query.opcode == "Query" 465 | assert dns_query.opcode_id == DNSOpcodeID.Query 466 | assert dns_query.hostname == "www.example.com" 467 | assert dns_query.packet_uid == 123 468 | assert dns_query.type == "A" 469 | 470 | # Assert Remediation and KBArticle 471 | remediation = detection_finding.remediation 472 | assert remediation.desc == "Description" 473 | assert len(remediation.references) == 1 474 | assert remediation.references[0] == "https://www.example.com" 475 | 476 | kb_article = remediation.kb_article_list[0] 477 | assert kb_article.classification == "Classification" 478 | assert kb_article.bulletin == "Bulletin" 479 | assert kb_article.severity == "Severity" 480 | assert kb_article.size == 123 481 | assert kb_article.src_url == "https://www.example.com" 482 | assert kb_article.is_superseded is True 483 | assert kb_article.title == "Title" 484 | assert kb_article.uid == "123" 485 | 486 | # Assert VulnerabilityDetails 487 | vulnerability = detection_finding.vulnerabilities[0] 488 | assert vulnerability.desc == "Description" 489 | assert vulnerability.is_exploit_available is True 490 | assert len(vulnerability.references) == 1 491 | assert vulnerability.references[0] == "https://www.example.com" 492 | assert vulnerability.severity == "Severity" 493 | assert vulnerability.title == "Title" 494 | assert vulnerability.vendor_name == "Vendor Name" 495 | 496 | # Assert OperatingSystem in KBArticle 497 | operating_system = kb_article.os 498 | assert operating_system.cpu_bits == 64 499 | assert operating_system.country == "US" 500 | assert operating_system.lang == "en" 501 | assert operating_system.name == "Name" 502 | assert operating_system.build == "Build" 503 | assert operating_system.edition == "Edition" 504 | assert operating_system.sp_name == "SP Name" 505 | assert operating_system.sp_ver == 123 506 | assert operating_system.cpe_name == "CPE Name" 507 | assert operating_system.type == TypeID.Windows.name 508 | assert operating_system.type_id == TypeID.Windows 509 | assert operating_system.version == "Version" 510 | 511 | # Assert EvidenceArtifacts 512 | evidence_artifact = detection_finding.evidences[0] 513 | assert evidence_artifact.api.operation == "GET" 514 | assert evidence_artifact.api.version == "1.0" 515 | assert evidence_artifact.data == {"key": "value"} 516 | 517 | # Assert Type 518 | assert detection_finding.type_uid == DetectionFindingTypeID.Create 519 | assert detection_finding.type_name == "Detection Finding: Create" 520 | 521 | detection_finding_json = detection_finding.json(exclude_unset=True) 522 | 523 | url = "https://schema.ocsf.io/api/v2/validate" 524 | headers = {"content-type": "application/json"} 525 | 526 | response = requests.post(url, headers=headers, data=detection_finding_json) 527 | assert response.status_code == 200, f"Schema validation failed: {response.text}" 528 | assert response.json()["error_count"] == 0 529 | --------------------------------------------------------------------------------