diff options
| author | GeorgeFI | 2023-02-20 15:33:46 +0100 |
|---|---|---|
| committer | GeorgeFI | 2023-02-20 15:33:46 +0100 |
| commit | 21ee2d787fa6279acc6672fbe223717b928aa039 (patch) | |
| tree | e17206b354b272dcc2e1a36233c417204297b2fe | |
| parent | 599734647e9595e00f67349c8d4b42cb603f306c (diff) | |
| parent | c0084cff4161df63d6b372f0ceda4d12b5bbb787 (diff) | |
| download | sec-certs-21ee2d787fa6279acc6672fbe223717b928aa039.tar.gz sec-certs-21ee2d787fa6279acc6672fbe223717b928aa039.tar.zst sec-certs-21ee2d787fa6279acc6672fbe223717b928aa039.zip | |
merge: merged main into feature branch
74 files changed, 2245 insertions, 627 deletions
diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 2d24fa82..00000000 --- a/.flake8 +++ /dev/null @@ -1,20 +0,0 @@ -[flake8] -max-line-length = 120 -exclude = - .git, - __pycache__, - build, - dist, - venv, - certsvenv, - .eggs, - scratches, -max-complexity = 10 - -ignore = - # line length, should be handleded by black - E501, - # line break before binary operator, depracated - W503, - # whitespace before :, not PEP8 compliant - E203, diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 95de7f7b..9cb2236f 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,66 +1,44 @@ -name: Lint (MyPy, Black, isort, Flake8) +name: Lint (MyPy, Black, Ruff) on: push: workflow_dispatch: jobs: - mypy: + black: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Setup python - uses: actions/setup-python@v4 + - uses: actions/setup-python@v4 with: - python-version: "3.9" - - name: Install external dependencies - run: sudo apt-get install build-essential libpoppler-cpp-dev pkg-config python3-dev -y - - name: Install python dependencies + python-version: "3.8" + - name: Install dependencies run: | - pip install -r requirements/requirements.txt + sudo apt-get install build-essential libpoppler-cpp-dev pkg-config python3-dev -y pip install -r requirements/dev_requirements.txt - - name: Run mypy - run: mypy . - black: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: psf/black@stable - isort: + - name: Run Black + run: black . --check --target-version py38 + ruff: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: 3.8 - - uses: isort/isort-action@master - with: - requirementsFiles: "requirements/requirements.txt requirements/dev_requirements.txt" - pyupgrade: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Setup python - uses: actions/setup-python@v4 - with: python-version: "3.8" - - name: Install external dependencies - run: sudo apt-get install build-essential libpoppler-cpp-dev pkg-config python3-dev -y - - name: Install python dependencies + - name: Install dependencies run: | - pip install -r requirements/requirements.txt + sudo apt-get install build-essential libpoppler-cpp-dev pkg-config python3-dev -y pip install -r requirements/dev_requirements.txt - - name: Run pyupgrade - run: pre-commit run pyupgrade --all-files - flake8-lint: + - name: Run Ruff + run: ruff . --format=github + mypy: runs-on: ubuntu-latest - name: Flake8 steps: - - name: Check out source repository - uses: actions/checkout@v3 - - name: Set up Python environment - uses: actions/setup-python@v4 + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 with: python-version: "3.8" - - name: flake8 Lint - uses: py-actions/flake8@v2 - with: - plugins: "flake8-future-annotations" + - name: Install dependencies + run: | + sudo apt-get install build-essential libpoppler-cpp-dev pkg-config python3-dev -y + pip install -r requirements/dev_requirements.txt + - name: Run Mypy + run: mypy . @@ -116,9 +116,15 @@ virt/ # mypy .mypy_cache/ +# ruff +.ruff_cache + # log cert_processing_log.txt ./cc_processing_log.txt # Experiment results produced by notebooks -notebooks/cc/results/
\ No newline at end of file +notebooks/cc/results/ + +# Default directory for dataset +/dataset diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7e4da57e..7725ce34 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,21 +1,16 @@ repos: - - repo: https://github.com/asottile/pyupgrade - rev: v3.2.3 - hooks: - - id: pyupgrade - args: ["--py38-plus"] - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 23.1.0 hooks: - id: black args: ["--check", "--target-version", "py38"] - - repo: https://github.com/pycqa/isort - rev: 5.10.1 + - repo: https://github.com/charliermarsh/ruff-pre-commit + # Ruff version. + rev: "v0.0.239" hooks: - - id: isort - args: ["--check-only"] + - id: ruff - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v0.982" + rev: "v1.0.0" hooks: - id: mypy additional_dependencies: @@ -23,9 +18,3 @@ repos: - "types-PyYAML" - "types-python-dateutil" - "types-requests" - - repo: https://github.com/pycqa/flake8 - rev: "4.0.1" - hooks: - - id: flake8 - additional_dependencies: - - "flake8-future-annotations" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dd00667f..32f2f0ab 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,8 +33,9 @@ Note on single-sourcing the package version: More can be read [here](https://pac ### Currently, the release process is as follows -1. Create a release from GitHub UI. Include release notes, add proper version tag and publish the release (or create it from scratch with new tag). -2. This will automatically update PyPi and DockerHub packages. +1. Update dependencies with `pre-commit autoupdate`, pin new versions of linters into `pyproject.toml` and run `cd requirements && ./compile.sh`. +2. Create a release from GitHub UI. Include release notes, add proper version tag and publish the release (or create it from scratch with new tag). +3. This will automatically update PyPi and DockerHub packages. ## Quality assurance @@ -43,11 +44,10 @@ All commits shall pass the lint pipeline of the following tools: - Mypy (see [pyproject.toml](https://github.com/crocs-muni/sec-certs/blob/main/pyproject.toml) for settings) - Black (see [pyproject.toml](https://github.com/crocs-muni/sec-certs/blob/main/pyproject.toml) for settings) -- isort (see [pyproject.toml](https://github.com/crocs-muni/sec-certs/blob/main/pyproject.toml) for settings) -- Flake8 (see [.flake8](https://github.com/crocs-muni/sec-certs/blob/main/.flake8) for settings) +- Ruff (see [pyproject.toml](https://github.com/crocs-muni/sec-certs/blob/main/pyproject.toml) for settings) - PyUpgrade -These tools can be installed via [dev_requirements.txt](https://github.com/crocs-muni/sec-certs/blob/main/dev_requirements.txt) You can use [pre-commit](https://pre-commit.com/) tool register git hook that will evalute these checks prior to any commit and abort the commit for you. Note that the pre-commit is not meant to automatically fix the issues, just warn you. +These tools can be installed via [dev_requirements.txt](https://github.com/crocs-muni/sec-certs/blob/main/dev_requirements.txt) You can use [pre-commit](https://pre-commit.com/) tool to register git hook that will evalute these checks prior to any commit and abort the commit for you. Note that the pre-commit is not meant to automatically fix the issues, just warn you. It should thus suffice to: @@ -60,9 +60,7 @@ pre-commit run --all-files To ivoke the tools manually, you can, in the repository root, use: - Mypy: `mypy .` - Black: `black --check .` (without the flag to reformat) -- isort: `isort --check-only .` (without the flag to actually fix the issue) -- Flake8: `flake8 .` -- PyUpgrade: `pyupgrade --py38-plus 'find ./sec_certs/ -name "*.py" -type f'` +- Ruff: `ruff ." (or with `--fix` flag to apply fixes) ## Documentation @@ -1,15 +1,15 @@ # Sec-certs - + A tool for data scraping and analysis of security certificates from Common Criteria and FIPS 140-2/3 frameworks. This project is developed by the [Centre for Research On Cryptography and Security](https://crocs.fi.muni.cz) at Masaryk University, Czech Republic. [](https://seccerts.org) [](https://seccerts.org/docs/index.html) [](https://pypi.org/project/sec-certs/) +[](https://hub.docker.com/r/seccerts/sec-certs/tags) [](https://pypi.org/project/sec-certs/) -[](https://github.com/crocs-muni/sec-certs/actions/workflows/tests.yml) -[](https://hub.docker.com/repository/docker/seccerts/sec-certs) +[](https://github.com/crocs-muni/sec-certs/actions/workflows/tests.yml?query=branch%3Amain) [](https://app.codecov.io/gh/crocs-muni/sec-certs) ## Installation @@ -57,3 +57,9 @@ df_2015_and_newer = df.loc[df.year_from > 2014] # Plot distribution of years of certification df.year_from.value_counts().sort_index().plot.line() ``` + +## Authors + +This work is being done at [CRoCS MUNI](https://crocs.fi.muni.cz/) by Adam Janovsky, Jan Jancar, Petr Svenda, Jiri Michalik, Lukasz Chmielewski and other contributors. This work was supported by the Internal grant agency of Masaryk University, CZ.02.2.69/0.0/0.0/19_073/0016943. + +
\ No newline at end of file diff --git a/data/reference_annotations_split/test.json b/data/reference_annotations_split/test.json new file mode 100644 index 00000000..41ac06ee --- /dev/null +++ b/data/reference_annotations_split/test.json @@ -0,0 +1,780 @@ +[ + "11a98c5d5ff6f40f", + "6dde54b8c6d592ef", + "054bd8196e015197", + "c902a788d699fe4a", + "5d674c06a559a5e7", + "9f8c9a3aa64a9f8e", + "9545f2b0b8b92c8d", + "56ceb1a9c003ac3f", + "9299f6cd8a266541", + "d1fe94ee32cbbf05", + "6313a92bf426d2bb", + "e8a37e48a8d34410", + "f34df0dd7011366e", + "c23218b044706800", + "3f4b6e4f245f6fab", + "5f99b00bf258f32f", + "4f3bf0c433b7f54f", + "587055293e9fa51d", + "da2d3567a814d2d7", + "915e919390e6f58b", + "a5e8267322d0d7a6", + "82dce1546c69369d", + "7d4585a4b5b6e873", + "736ede0289146b59", + "0cbcee9f1cde47a8", + "4bf7d6ef245dd393", + "3817c0aca007989e", + "baead73ecc6e4a33", + "19d3185c40be008d", + "8a7731e9eb363fb4", + "78a279b07a6d3367", + "47913a485c3c8a18", + "5f259ce91f0234a0", + "d4a14ea7adb375ed", + "994a2bf994b4facd", + "ac1257069b2f4afd", + "b5985efd378af972", + "bc1452fff95744b9", + "4f953ae00a24eb85", + "a35ed74b7ea3ec4b", + "654554952ecb20ac", + "157b741a0f529a0a", + "30ae700d801bd41c", + "2f9feaf4121720da", + "e0283686d26420d9", + "1b2764a62ffe86a2", + "b47b457f73c42c60", + "ff45605151ec4eb1", + "5346d5a4418466ab", + "e5b04a0a3872954f", + "981f7ea91d7bdcb6", + "f229a8078cb4ff82", + "731aac44217611ec", + "4e29916c366fe997", + "5efe98a1ba4df4d7", + "ffd213e55eee8cc8", + "7e24168630d5124e", + "00ad121fa63e5dfb", + "173097995b7a7f12", + "4b2f963b48e0f954", + "5e4c757231135ba1", + "aed7a612d966a786", + "1468948b4f0509ab", + "4d885e54f1361d04", + "8a5f8686ab9de19e", + "37d28734245a3bb1", + "80fe3ba3d9c9bf64", + "b1b385d5bad724ed", + "c4ca6565698f0e49", + "d9bfffa3cc6d1c53", + "d32e5d4d5ff8b871", + "8865aed38c79d3fc", + "5bf118ffa29520c0", + "6136acacc653106c", + "05d96aada7bb839c", + "0aad0176e35b3749", + "64ed7e55bdc50177", + "3976c9e492193315", + "65fba51313f65938", + "55e52bcaab69d573", + "4dd0daec78093d31", + "d67edade78d25033", + "71eae9be60b7fb6c", + "3d149fe7c08bfc58", + "1d9ae732c5dec242", + "6bdca9f13e19572e", + "d6ade0a63d0f9130", + "da1139ecdc3512da", + "637657613004dbbd", + "29fb07d8f74e734b", + "075ddd00e07fa7ed", + "ce92195cf4a19084", + "68875c05e00bd1aa", + "61e862ed07d3cb03", + "cdbbbad526f0aa13", + "1d1df0fb541e49b8", + "5d4aae047020163b", + "c67724216ed5a318", + "10229cdd92c1989f", + "4dbb108406acb1a5", + "9292ab2134e8a712", + "84501b4439b66fd9", + "35efe13fa9e93a68", + "5c5431cca026fb3e", + "e3a743ef04ecfb64", + "89d1f7ab8b77e41d", + "70908a4cfdc5585c", + "8035f242b12cec6d", + "67240adc18be338d", + "3e08a27e9d9c9b1e", + "5eb91b620bbf5bfc", + "7e92dcac20e009a5", + "49e6665ee56d3bfc", + "54fada9909a1edb3", + "8ae9a7fbbb50b6ed", + "61e7ec1c62704f39", + "f3bedaa5ffeeadb1", + "a3d152e25f8ce6c9", + "de2ce0c1b72d5c90", + "92ae986997c1d45c", + "29cc495628e76ffa", + "83bb8420c3cccf85", + "ddd9691cb063b07d", + "693325ca20a6325b", + "37b94c08f8e25249", + "26c7b173668167d8", + "60ec8738947badb0", + "37fe6036c2ac932b", + "d69309b0a27c929c", + "01e5c6d31f763f56", + "adc6971cdb0613b0", + "ffc97a8fff838fa8", + "9ac6a8bda4fb7dc4", + "e247b50a301ce26c", + "e359ab2e436adf36", + "723ba544431f7874", + "fff289a66cb9ce4b", + "583c12b5bf2423c6", + "98a578f7758bb518", + "10233188161519ee", + "123c94418ddf1ad8", + "0bd651fcbb86f2a9", + "6a46ff1d1a5154b0", + "a5898123ec124b34", + "6fe5828936663aed", + "5506b5232076d409", + "1ea31bb5f6a15995", + "45098872448f5816", + "112fe9f123e277ee", + "09220515a7edf3f9", + "114e39b4da949e6d", + "621335449637e335", + "b82b48b0e915aaac", + "db9267bdc717c801", + "195366bfba7213a5", + "177dee4c1051e612", + "dcd67613012044b3", + "60f0dd83c8f32b8c", + "bff1330c13ccd99b", + "c06c7eb3afa4aea0", + "9ae7edbd0444982d", + "ec21d3c76c5ef65d", + "449c74a92ebb61a4", + "23a85a7f9c07412f", + "7942e835fb18c4ac", + "51c589803c349e44", + "f577607298c4b574", + "8944c4f14bbcaa74", + "f1a73b2232787b26", + "96c904c81aa2a241", + "0ef56cba2362e463", + "b965c3b6a03aefc4", + "35b9be2203d2b9e6", + "da6845ee99cfa275", + "977b04d04def60a7", + "7d3546a4000b5b75", + "82a2bd8fe4ed2087", + "135ca3602f0005bf", + "95774db1eb19b767", + "83020f91ce1aaf68", + "950ba1c7368c397f", + "98642c6f99438194", + "b7209eec8fe7fc58", + "b21be5dd6fdec83b", + "60f08c85a518de1c", + "62eb991153211de6", + "f9d9fe0dd9f7f110", + "017f3cea8275a3e1", + "b644b78aafc367b0", + "808de32aa819821d", + "cc99b5d3806b1e97", + "d07b6e3036abb8f1", + "db28c1d7f201af1a", + "997281c99ac93b3b", + "a596f2412c0f8fe2", + "dc51cf4e51f01086", + "692e91451741ef49", + "d3d257648d4c3105", + "d6d129c94c368155", + "f9a3871824bcd47a", + "d063a93beba2dd65", + "e4dc90de190437b8", + "3feda0b8b5637540", + "8da3e1e348d36e07", + "d905d620783d3768", + "bb509db67c18bc40", + "902dbd430adb77a5", + "cb9a110799bc37f8", + "41bd2924e9afced5", + "a2cbd066271b6b3b", + "6587b26878da24b5", + "5498bfcecf19dfa3", + "2e997ba7beaed34d", + "0208e6b60a0b1a32", + "17bfc3d0570ab3d0", + "c459c68e95d54f87", + "0a6525cdbeb38df6", + "eac2041efb4cf9f7", + "a9f542d8e2be69fd", + "be9ca77bec616fe5", + "09f539aedefa9756", + "86e9da10bc176267", + "ad2351479ff6ee84", + "6b605ff743c859d0", + "59820117bb7fa240", + "f5a53fa6d2c3d9b2", + "9cc6c08cbaa694f2", + "5ee9898421c06859", + "93f14cad1cb201fa", + "183a5cd3e2aaa0ec", + "53bba35f7ea6edc9", + "6eeed6fefb1f0243", + "8b0204e041dd3eb8", + "7386d04b20f354f4", + "a57845715134651a", + "2a91f42389fda90d", + "f7cbb33cc639b5b5", + "b5b8bd0cb8bb7658", + "86462bcec4492bfa", + "75c08d873d0dcc06", + "6d9c2bab8cc8d28c", + "102bbdfcd696d7a9", + "bbc9a3a1d685d5f1", + "ce22219c2049985c", + "e2a45ce49bb2b731", + "21cffadbbb87c205", + "b4768c31e98b2170", + "16b0a0811bc4fe82", + "0ee132dec087b772", + "8bc3658bc958f81f", + "18b7e5bdf459ca13", + "f2516946c797b1a0", + "e56d5d27cb2b3e6f", + "0a6e50445a906052", + "33cada8c95bf55c5", + "ecee66b37d7576db", + "bc25a76284e7c7ce", + "e9c5d02aae54cdc5", + "b3855f3a6c06c01c", + "b24a14935edd51ad", + "69b877d99c360f97", + "f731aaaab07bdca2", + "7980d204dbc3ecee", + "8c6c4b4606608dfe", + "6e9496b7254e02e2", + "aadbb9992a672a1b", + "ca1fa7c3f26bb3c5", + "27ccec0740bb7915", + "ee4e169753085913", + "ea4f0c0a7b82f526", + "16f1a518cd842fcb", + "83c1ee8ab43ea00a", + "76d52f916b4222b1", + "4d2a177384b23fd6", + "43a4ca62d0c0b0da", + "e23f9c02819688f6", + "16b24ff1bf3c079b", + "cd72fc2b62780a43", + "6eacef3b2f976ce9", + "fbdaf22c4f50391c", + "107c348f4ba0a41c", + "fbe41655a05a01ff", + "39c07ebbca541145", + "173704f0d2b8a02f", + "096b05114ee5e09f", + "a289b9d43310182b", + "cc6918e95b803734", + "5f84cd800ee96468", + "07ce7e4844f62c5c", + "22ede463dbf1a105", + "8ee7145a1b48b578", + "85fa17a19251a2ea", + "58ece75f7f2b5099", + "420876ec1e5ba657", + "2d0b4100c3ead88a", + "42f53e51476f1a3c", + "96c685a3cdd9ed59", + "eacc2cf0173eb438", + "9938be53082a02e6", + "d75ff490c057793c", + "7dfcefd1ffeaa941", + "131ec924c42ef90b", + "d3323745a51a604d", + "2eee0fdd5cdaf565", + "bdf8d5624e230986", + "7096b882b315807a", + "84b1520706c3d784", + "b49efd086851f84d", + "e56e14e8cbf89e3c", + "3183669bf78db43b", + "c28289a45fc012a6", + "a14f221cf1761a8c", + "e7a197d6aefb66df", + "0349c893b81f7c1a", + "84ff17001564ea47", + "b1401488f998c1f0", + "e367ecaf05dacedb", + "6f90b0bf6bbe884b", + "4abc83fee59586b2", + "e64266a9c13fc74e", + "37c8d23c44b95833", + "5edefd19948ad581", + "932cef2b9698dde8", + "158950ed4bc35274", + "4dc023ea2e3c4115", + "8bbbd89d09bb82ab", + "ac4687f4b15507b6", + "3392558f04e04663", + "64e80c255d51ff37", + "78ef46252d580af0", + "4b5521f85ab3fff7", + "6c3e0fe95400f1f5", + "988394e53c8e52d9", + "983d431922822165", + "0319b03323f257d1", + "3a3b0a9113835307", + "91108cfcecb98297", + "b883e389d34b1bb1", + "af58ba642f4fc3d2", + "b0fd694500bfffab", + "d7501476836cf315", + "1cc05dbb992431b9", + "d4a1feebc1e1cb5d", + "ea316d47c03f9fdf", + "781c243d0021d4c5", + "aa3f466daa34d3ff", + "568c473e6e5e95c7", + "cdecc0eedcf05d2c", + "d3987535a95fbffd", + "f4da9e13977580f4", + "c483baec90d76587", + "6becc4c21730d391", + "7c04881c9a46b337", + "a93edea77d9f3338", + "c1e14f36f031a342", + "b12b4e4eacad1497", + "fd583001a87023fd", + "63e55780fa1766de", + "58ef8ca403038960", + "b9a6922899b66b8b", + "0ff82b1cc24b3105", + "0c9e215997d96f44", + "f0bd6a29eee94a2c", + "4f8db13958be0f75", + "c4f5a7748428e7d1", + "adc9df2489ce090a", + "e3231fac88242d81", + "c62b878b1ac43df9", + "a6c1dd30884a197c", + "5469d2b3e5fb8323", + "f588fbe6fd36bc6b", + "04c5a5a66fb7f89a", + "34ed76f0c32d9e93", + "6dfa24c82e89436b", + "d12a50d33b1c4253", + "ab88698a0c6ee1bb", + "13e5b88ad3becb77", + "cce214002aca738f", + "b6c3a9d53b9e784a", + "b1b04d862f4c32af", + "dbbb56b48acbaf22", + "adb678f7143014a0", + "e0999b85d2f77733", + "438b59086f6ebd64", + "6700028a309c3f7f", + "9337ab9573b366c1", + "4c0e2794cb729825", + "6f480809fc73b635", + "2760aeedce0b79db", + "bec58e970e8cd6c8", + "d3420c2bf8974a5d", + "57e929939f1fd1c0", + "65a47f93451f13de", + "b168db2651cbc1d6", + "75609423e1f40c07", + "0d4a95a8b52b787b", + "296618f10b019d9c", + "fce7e01f2cd0cac0", + "36641ce7192b5f92", + "4d21561351ecd00a", + "06b24bc51eb69188", + "dbe20d7c305b24eb", + "dbcf1311b3d95cdc", + "51a4bea9a77a55cf", + "9f400f89490fb8d5", + "55669bcb3a9e09c0", + "6337d3dcc5362dc6", + "55f9f2fedfc7f069", + "3d756c83419bba28", + "8f3037c89c498e88", + "2be10f342e68a89e", + "e501cafa3b025fb9", + "42bc15eb26cf2eec", + "05822f92f304fcd6", + "44becd7e128f4ba0", + "696c193b3d13924e", + "c5bc8b961a199646", + "2a07b85f61ac08b0", + "5cfe68ed449e0478", + "02c6fbcd90dcf05a", + "4285d9b580f8a2a6", + "16513a1bff79b46a", + "a334142059d865a2", + "a67919286833a7df", + "2078424be58e4db1", + "0f684159ad31f883", + "a76054a284f0ce61", + "8870ddf70bf57890", + "15b121492722bffb", + "a781ac2579798523", + "bf1338e9abe85c39", + "86f1afdbbd29e48c", + "afcf1165734847de", + "f569fb2a6ddae452", + "882a9d016c7e1f36", + "b584e424a8b3dabe", + "d80c26c2484dc87d", + "30e9ce0969941ffb", + "8cfcf8dc64485a74", + "d1df1bf926a69ca9", + "f621ca835cf98a6d", + "3519c14e4114d93d", + "db28c203846775d8", + "2d046178aa118fff", + "40fc6ad0aed92913", + "48d897f17754c7ce", + "b5968cd571a14cf3", + "31fd07069aebf013", + "c18dc9f29967fe7f", + "afe441f40a42865e", + "f8a3fde3a557f44d", + "c8e381408b191a02", + "f9e9366287e79e4d", + "cc64f3b8666b17bf", + "e535b7a4343399e7", + "01ce6f422bec823d", + "e64eedbb40d09a50", + "ca88a34b0fcc5b0e", + "bd346dd3e46dff68", + "966a03f9f111aa35", + "b95f2b009d70fad1", + "337ece90615ed69d", + "f14484e630df1dec", + "10af4a6378d0fb7a", + "5cec11774890d61e", + "b99c572f58cfb19e", + "b6c15035f759ec50", + "975dae6e02765a90", + "c96ac4c4015414ad", + "ea1b5ef156502d98", + "082380caaa153ee6", + "1ff08f79cb89c1de", + "87abd998f3b7e26f", + "13d2556ef392ed41", + "00a2b91e5b58cef1", + "cc5a3d2a52f99ab3", + "7a5a4a9578503a55", + "59b026d889aa0309", + "157f811757a0b29e", + "8825e2c99223c084", + "ed511caf8988dc45", + "04cb360502da6492", + "d317c9c2e53ce427", + "f9fb8170cecedc23", + "e3129aad84d5c40c", + "bb21cecb8bbfdf63", + "46459cfb9c1045d8", + "102707a8c4d8a1b0", + "2bd9661657e78278", + "a191b2da409f3518", + "62313881916550ca", + "e5863682239df24b", + "c572cacbeb840621", + "e93cb94a06c6957e", + "cc5e2f58b681e555", + "259e0ab1c4b690cf", + "fb2cfdfef4f93536", + "abef2b316c54f9e7", + "7f02a580f5219377", + "819d92a6492415d3", + "dd4cfd03d9b3f25f", + "996691f0e03e303d", + "5e4e16da9d0630dd", + "5162627872566ada", + "a465a767ceb7fd30", + "cce1a95634c6972b", + "7a26d92281df3e8e", + "109eb2158ca6a2f9", + "743318f3a2b4e281", + "06998c36415036aa", + "a49706f436a6873d", + "75ce95f62fc65fac", + "43d9cb9d3fe30ff2", + "4871a084d74a4bc0", + "8ade0910a89717a8", + "00b539d629e60965", + "74d685c3723bdf92", + "d08b5ddedd34448d", + "6999db84bd629b32", + "f7941427d5fa40ea", + "92c7355f5ea28e52", + "0f7ce013d15f6ff5", + "7b63c31cfd0eb65f", + "15fae84c1e6c6c57", + "4eb33712d4b16f43", + "67e75c6c6538110e", + "8817adf6eaf4f06c", + "97f302708066dc04", + "02cb3c385865ad2c", + "c6c291cd525225b7", + "f2e7c6dfd6a431c8", + "8820852f4a1163b3", + "ec8a2a25cdbda634", + "5bfbc4a6cbab9eb1", + "491c766e35ae9f6e", + "3f22bd3eaef5d64d", + "c497da3fdb2f5027", + "b6e60b9025d116e4", + "e89a1a7817dae7e4", + "15ae64b85b3e28d7", + "7e8763f553e43d12", + "691b730a7bbb28b0", + "8d92202f35f15712", + "d34363168b1590bd", + "e6aaffd588f2832e", + "57e108dcd6ee072b", + "6529877d9799822a", + "384dca297bd4f1ca", + "b764f5d5391e431e", + "b5b8de155e4e40e6", + "d4647f5217d84ba3", + "dbd62ef3bd952bad", + "8dcdbce3262bfcd6", + "835211383d281d89", + "b7132fe23fbdf9e1", + "de50abaf95e79d34", + "c621d1371b314913", + "6ff89f3123a6a98f", + "5caf1c90ec7001b7", + "596a0fd33f70da59", + "40fa0a4cb5193977", + "d3c2a59a2cffa30c", + "9ba1fa1ae8c3ae67", + "598e2a9978d3c79c", + "08bff656ff61e949", + "0160f6becf137107", + "f67f3737a3b47208", + "c3dc8cfd97735115", + "541da571bac5e279", + "55925bc39df20912", + "af78198822da03a7", + "6f13e8b708b43383", + "5787ff8207fd751d", + "424f6d496746258b", + "2c41f9dfcd5014e6", + "e6dd3d435bd1b82e", + "a29d46ab6efee468", + "f4b4b026e87b5086", + "ae175aa839dbf692", + "97eb8171b51f9aad", + "a2a5ccdf0846ce67", + "aeb79c7e573de0e5", + "42d2e68c29d9eef7", + "f1300cb717ea9335", + "9231adbf747903df", + "e9845b4128afd538", + "e0be32a08b66d264", + "8f7e22207cb3dd8b", + "f68006f6c05e1211", + "40f62cd468a546cc", + "56ebfd7a918891c6", + "cf1c544add4bf860", + "c1754dc2e7d666d8", + "a4d0e44f4527180f", + "3a6a5f536bfbd4d4", + "d07cacdb732c0b0f", + "9973eb31c46f8637", + "925da3b468003e72", + "7c7e48e3aed8bfd4", + "24624a4e60ddedd4", + "3e182053b03f1faf", + "7a059d2754e088a3", + "e6959c2b66202cb8", + "b252ff42ce0b7443", + "5f4cd1504f8b18e3", + "be080cda1829826e", + "0f1b31ac93459d1f", + "ea17788d9a9d12eb", + "5103648897ba1b3a", + "b887b7dcd6f1fdbb", + "1494cff85b3dc2bb", + "2adb03f5294c31c2", + "5cbd46653c3bea1a", + "259df98e7476a843", + "c4e6a655a15144dd", + "9b30bcdbccfd4c68", + "84444ea4fabcc66c", + "01dc77d7f8f94d97", + "3ea02a62856c752a", + "e8adf99d340489ce", + "65af80e5c6538215", + "a00e93f2981ef418", + "ef02bc67ebead2a2", + "9be76c10474e0c80", + "54f754dc95137c47", + "a0621c7e36e9ecb1", + "797ea41cc2e95f08", + "b4fc6a7b6c200b1b", + "fca98ecd003e1b82", + "a5451ba38050a44d", + "58688dfc2c59d3ab", + "f2327302df1aa660", + "30c6777901ae346c", + "6fd73557577cf9ed", + "96b0895b9f712d2f", + "e92ba97c2742e63d", + "fb1fff87c87b82d6", + "122245dd15683e26", + "34506b8fab6dd7c3", + "8cfd0c9f4bcd21b8", + "5b1b55f1997a9439", + "09b07fbbb24e1b04", + "f2eb0ef953f3f147", + "7e9fc9f948e5cb17", + "4893140ae5daadaf", + "f2fd56c195593dd8", + "953e132dd43ec03f", + "1c8567a1b1a6c12a", + "48a41f3f5110db1f", + "032faef0207b715f", + "d2bece2b0eebce5b", + "8d2c50e41a1a0061", + "a9004216663480de", + "8f7cc0f456186028", + "10b17081dd7cad8f", + "6ae356d8abbfdeb9", + "1bcfaefe46abccf0", + "8f81bb35e37f1b4c", + "51768783ab3e67f3", + "b6a96b0dcf6eadf0", + "5b67a83de2aaa93a", + "4c90a96fb1ee09f6", + "cecb6a5d441fba98", + "48fd3d84b1a0bc68", + "00eb3e5c7a4537b1", + "3f188bbf2af01b25", + "7e37ff763a97bc72", + "3ba9f330ce93636b", + "21951e191e55b66e", + "ba521df2c728c5a2", + "ffe4328dcdc6b538", + "ae9574428bd713e6", + "ff0ffb9a32873433", + "56a56d39dbfe3516", + "a925d8f1adc5cfe2", + "7c708f62e3280ec3", + "aa0213dd9f727219", + "3334d22b6559d0e2", + "b2436dcf1c8e5dc5", + "8d68ee5c283ca6b0", + "4057f5dbe4ffa4cd", + "18a515a0fff0c0c3", + "4832a44c0df0bad2", + "c8fc487eec95c21e", + "8782c7c292ef2759", + "36df04ab9c978ab9", + "06e70fa70393d60f", + "559e0907fef71cf6", + "af373587f2c57a24", + "3746512864b941d4", + "1999d4ed82b3188e", + "793075287bf70a81", + "878af76320373ba0", + "ca63425a882729f3", + "95c52fa37ef1eb3b", + "d2d43918e5447c09", + "ab769495f97aab9c", + "2b0342d5b70b7a78", + "ee3a996c18ace68e", + "9d36f8ab4e1b45dc", + "3d8083b1e6c7b336", + "fa8384342c25ec59", + "373e7b1bc9066563", + "26c4912b140fde9f", + "d71d0b082233758e", + "9be0c86102117436", + "f70d226e1598ac41", + "328fee1e52f7ac82", + "70f75a14390522b6", + "1188aebd8681e4fe", + "08408cbc394e7421", + "cc932dbc293df39e", + "d5187fc1cd590073", + "0b0648a9b9a26747", + "0cd406e7c5013b74", + "25c07c5d0a05d86c", + "9e55246befe96fb4", + "a0fff0700364df49", + "f9d96d0eb2bc85cc", + "5eda77c801e2df86", + "ab8cf6af80a5c0e0", + "73dbc35c2b91c4fd", + "8e713eb632acc712", + "56bca69ce012d4c1", + "bc715a45d7584d95", + "bb02df07a0d95e77", + "5423483cd3c3b75a", + "6df8f86449e56c05", + "3e345d3c6002ad55", + "29f2dd90f57ea948", + "ee6718f7a7e3d30b", + "ea330145d3ba738d", + "fb8010928a4bb56b", + "921ecc7c3e5f4884", + "940a18f62c79ffae", + "83b4d7d35a747d1b", + "b15c099c68671895", + "f1b9158cc2b98388", + "8b7145c13f36c324", + "37e0d3cb098458d0", + "080aa6966d757f05", + "ee35d872179a1397", + "6abef2102c86c0fc", + "096ccb6bcb3d2731", + "71d3720cad53b289", + "15ee7651b7ad610c", + "0da9d81c9f563df5", + "6ef82dead8e3437f", + "fd966f807d3ba9fe", + "b804c318fc0c1e9b", + "4750f5114dcaa60d", + "9e7c513fdd35df17", + "b2ba4d07e03b47ea", + "cbe5be4b63677c25", + "53fe111411edfa45", + "87a80325171d8add", + "3f8475de6ea558ac", + "a64e6bf63ab6a299", + "c10a3a62bf9fe782", + "711a7b593ed41b02", + "5a1764ef77908457", + "6c2fc8308efeccb4", + "1ac8de53c0894d18", + "bf0f48ffd0dff903", + "a851c3b4377f4923", + "f96bfb09bb1bd640", + "fd3f988b7a505c45", + "84c8bf1f809380bc", + "c16f3dafab92df61", + "55e85aac6594c2fc", + "6cef8442092da1da", + "1172a88e009dc248", + "af4c9b6e93062fde", + "96106c2d31eea8b2", + "c518dd59d12daf17", + "871066e9e2eaba52", + "acee5f619f09bf79", + "0fe0bb1054f49b7f" +]
\ No newline at end of file diff --git a/data/reference_annotations_split/train.json b/data/reference_annotations_split/train.json new file mode 100644 index 00000000..b2e65750 --- /dev/null +++ b/data/reference_annotations_split/train.json @@ -0,0 +1,466 @@ +[ + "412316e54e63beef", + "ce3ee1fa409676b3", + "cb862d0020c32547", + "bda89f3b2429ab6a", + "388653542ec9fb6c", + "7f1f7bffe46d4c85", + "0f1bd208c27d202c", + "b8370ceababbca40", + "12e20466a0f08342", + "9b8b9b7fcd97bc60", + "32e083734907ad15", + "294ef6cb28408ec9", + "f17fe9ceea628f62", + "6f38b9bce48590e3", + "b61363e51ed90c7a", + "9328c028356ab522", + "11687f8008b8198d", + "12c3b8b612c581cb", + "db3b58c1836b220e", + "f87b5bc03e18d010", + "a3de319045809828", + "ed22d4c0f09c3e3a", + "09b1192474bc8b27", + "d4e1874210b91dd4", + "c9b0cae8b5784d2d", + "dfe9de5d26e08949", + "97d00a9f198a6e57", + "d75282fdda80b6fd", + "6d41460480570d22", + "a7666a5157a31d32", + "5c3806bf79eeab7f", + "d2d0b2521a1f186d", + "6dfe436482047387", + "7e426c62da58175b", + "9dbb21687510991c", + "2b2dd14fee46498d", + "cf32640f396edb87", + "4d5cb991d2675a6a", + "751a324c3f87f58a", + "8bb25a14b21fcce6", + "243291b6c7ecde61", + "13a92431f9683226", + "7f4d3b659fc17c09", + "dba4b5a166f9456a", + "768dda4099b6f2d9", + "668b5c95eb0229c1", + "1b797b27b981aafe", + "17b5257b3755a07c", + "1c34d31598257da8", + "775b1fdecba5cb81", + "e0265f0fb8e196c0", + "161216fcc9eb8d34", + "7574381766e293c7", + "9529eb793550093c", + "4960693ee45f2ae6", + "cacdfdafce47678c", + "60f3bd10ee9be85b", + "4f5f41ecf7517e63", + "c7fc146c5ccf4821", + "2477ebdeb9bcf4aa", + "6ca1063d82ab795a", + "d2a4b8cb9ae7fe8f", + "c2024b43eeaa96de", + "a6fe8fe0aaf2fa92", + "815d67f8292ad7c3", + "19c60923e31777e7", + "97d5f9e6e0a11e37", + "c39e6ef4060594e2", + "a76d1c0d9964d583", + "a52f807db0eb7fdb", + "6e4de0c194952a21", + "317713948b4473b3", + "73e4f65789159996", + "54375fc2889bdfb4", + "2731d8ddba404fad", + "617810f97f3f0b4f", + "e8e5f42a4e4005c7", + "03aded94fb04c62e", + "1fb1564dfb0f0b04", + "e7e366f3619b5953", + "cd43abdf668dbb23", + "1fa2284c3dcf136a", + "c96343baf608174d", + "c32378a010479b33", + "99223aca5d9eb3b3", + "678b2b51e429444a", + "727bce62137f97b7", + "62bf5de838cd3a7c", + "732271484650d27a", + "b42009eb34746731", + "2b944ab6ce8fe8e1", + "8ff91b407ccd4b18", + "8fbe28bc70a821bd", + "86255c61e33c2caf", + "49bf2cf97dd4ca29", + "9776cff7d7ead7bb", + "69347104bc7e740a", + "818f62b997d143e3", + "bc17c54936484a90", + "824a8da5564344a3", + "fe223a9f01625d62", + "4c3282bd1640fcbc", + "ee1c6dd97918d74a", + "ace99e269d2a1bd9", + "4f3bf2d41fc130df", + "ca5da2fe138af656", + "41fb9717f70d3037", + "de9a98c311683ef3", + "bc260c38202644f4", + "30120e4f3aa2f30a", + "e66a9b22df7fe32d", + "559a5c3c4c23a9d3", + "3515801dee00995f", + "f20be2311365981c", + "e10bc3422afaec8a", + "5734ff91ea85611b", + "dabbb27e6faa13d5", + "7a8d4ed693d443d7", + "d94b13d95fd1c12a", + "e2e705cabd42e40e", + "b434dea9be2868db", + "e9e12b044b495c6f", + "a07548a64fac5794", + "5df7b3241b307f8b", + "18e68a485e648ddc", + "01e8805514b4ef67", + "13d95239226aa537", + "3f87aa90c0aaf83b", + "f2dc875bd399a806", + "a83fe0ea2f391ee8", + "7793c695818500d2", + "a38fbb576027f6c6", + "2f418fb3ced3820a", + "b5b0e3205923e723", + "627bfd69c2a831cf", + "e0b122da55f1f002", + "f6579adcbf5faa99", + "b33eaac3aae2f1e7", + "e6e8add5e4db2d9d", + "b0b7b073ca2dfe5f", + "fa67fbbcfc0b9442", + "af61a31e3fd0d6f0", + "fe445dc1c13738d6", + "0d08a211bd29f963", + "f02cf5078e4548e0", + "a276bd58a15d5be6", + "9d0a023ecd4ad7c5", + "0ff9337564f4f742", + "fbb507bc72376d36", + "6ddd0d9c37f27706", + "6a2323c5267ae0b7", + "744a7a202d909323", + "714559f7e1bf956c", + "c92a196d0408a5ff", + "f869956d14ea1694", + "34370b67b5e675c3", + "388b6899fb38b762", + "dd81eae9478576f3", + "8975cbb58ab67846", + "055985699aee1e09", + "1416afc51d8ce022", + "eea87713e11a55c2", + "44f1f74c09e634cb", + "598b6c745cdcd404", + "e9b7e07dc5598afe", + "0b3e1cdf3ef9413d", + "610e118d804e4076", + "fb9ec9e846ea4e87", + "aa096ffde94b953b", + "887afbb0843425b6", + "e2275acc4f1c2d0d", + "b3b7ac7aae87793d", + "95b2a54b81b0bc6c", + "77acb3a4a3f58e0b", + "ecfb020c517d37c1", + "9302a95ca3efba5c", + "ced6075dd1813122", + "ab3af998dff7a2ef", + "0f3900cdcd0c7f3e", + "d699ed2b1adc6be4", + "1e40bd733acd56bc", + "aea11fd4d2a7709d", + "cf7705e45048032e", + "1d89cece70c6cb64", + "f73d08f8cdfe276d", + "cfdacd53c732343c", + "9a94525307a1b13d", + "543d800fd468f0fc", + "25eade3365f92578", + "e886bfa3a4f4ffd4", + "b8437dbfeeaf0f04", + "05c03233d710cf54", + "18bb29b147e80caa", + "10107b83e7393c50", + "65ab2fd5467ef78d", + "10868774b23c5730", + "253e4d53f952a882", + "a47713a44e4c656b", + "f2e00a1fee27bdd7", + "4783477a22587a6e", + "15d935e36152eb15", + "4a6100f1ddaef93b", + "680aeb0a20a9fed3", + "14df54305cad83b4", + "188d3cda4e6f2d5d", + "fc373293fb7c56ac", + "79f48541164e16ff", + "e9fc2f8b110e71a0", + "ce14eb1b2318f054", + "12fd6b1b6c4aecf3", + "5f4b39feb2a82dac", + "0f040d1ec658b8a5", + "09be49631855ae19", + "c8ff17063166050d", + "76b289d10702db4d", + "eac7be8886cb755b", + "84c868322995b179", + "a515a81bc4be3cd2", + "b2bab86575d21b44", + "0eff4063e68d7cd6", + "32431779b1c54c0a", + "c118ee1ff2d1bede", + "1b0a6ecee1f830fc", + "cd052c606f2f9124", + "5deb0179858d78a1", + "dd1472476dfe4a8b", + "1a191f3535ccaea3", + "a9d336b90e8b94a2", + "6c222ea916b4f5e1", + "c5a60dbdb668bc10", + "f3a461d6bf980196", + "977477f3f0bf1bfc", + "1ee7ecee9e7e131c", + "d1a87288683080c4", + "185aa4f76ff15d62", + "23ce630f1ab642b8", + "7e9dd6cb86b58f95", + "b30ef2c1aaec9236", + "a154a01ff4cf04c7", + "79c729d80cb73939", + "a9639521d8a5ab09", + "f32a1e7e2843c096", + "8c21cafc192eeea5", + "59f15180eddee8b2", + "2ebb5bdbe7e00a78", + "bd1a21ea3d047c14", + "dbf15cc4f389196f", + "98f6f9dbb1540a31", + "cb203cf5d91b1ae3", + "f921d39906e6d93d", + "6c14f733fe7aa28e", + "f71fca5fc684df8b", + "7e82a1ceb29e4019", + "54273dd266fce692", + "536aac44b608f951", + "921e042759b30033", + "0167c92c0d8c8b47", + "90581f56f6846be5", + "a91ca8347f800ee7", + "dc278166b5d14512", + "90c290ed4ded479d", + "cee70006132a6f46", + "1357546ec01b1a65", + "5a66027d34aafc52", + "2c4caf71ca3735a8", + "0baac042dac42abc", + "54dd28994604ee35", + "60b45a1573fc53e9", + "6a999675c9422dfb", + "0d164fb0d72dfa00", + "b24f997d9358b324", + "df6728b8420ab3b4", + "d50ab8fd0c085fb6", + "9ae8bef18938d2df", + "19d14dec2d11fd96", + "f0ce40dfe333e918", + "3da6e0f0f97b3d2f", + "0d730f18ae9d5694", + "ecba01acba8df2ec", + "17a23970b35a4f44", + "1b8705a0486b3be1", + "1ca9b79a98ef45fa", + "66e47f5d28e2f95b", + "5f1bc82727f54376", + "9743174f44c5e2c9", + "ec84060a194fd9cc", + "845bb039719ac5d8", + "ea6d47427a2bb349", + "27d11629261d8806", + "6a5cb89e80f86ce9", + "29b0321ec6b75ebd", + "d355c778fcfee3a9", + "0ce083454814c1ba", + "c06d86db280f9b2b", + "b0e95af7c706ffa0", + "b9a973281ea252b3", + "d0705c9e6fbaeba3", + "a3210e75e10a3ba8", + "61832cb4291c343f", + "22dd52fbce13f27e", + "985ffde955eee01a", + "882df28aee338320", + "b23babf61349db1a", + "1c9bd4db3d8388f7", + "1ff5d648a625f3c7", + "691119fe8a2f8e1c", + "c30de3192d2e8ec2", + "5bf4e37462a1b715", + "de23f9f77f9b49f0", + "dadd7dd2d4247627", + "36ed04f4b45e3ab9", + "6b249c38b49ec9f0", + "a69ec271f8651d1b", + "7f9eb1b8217d15ad", + "6b003152c5459126", + "6eb6b29c45f6355f", + "502645d74f607b06", + "6d6ade44dcc497dd", + "3ebe69af702fa116", + "29c65bb00fb9aa6c", + "b4a2999b439b1ba8", + "3b0c5666e54a2394", + "8bdb610131555c12", + "b10ee0bb166cfd86", + "e676143c80802a59", + "15d68159595eae09", + "06b1a65aa87ffa78", + "5ee0fb9826fec164", + "2c15dfc106ebf8d8", + "bab97726875c0f14", + "a867d281d34d34b7", + "eeb2e28f54484dc9", + "d753660b3c2bdd84", + "5f7760ca5dd8b8ef", + "8ba22f6c9651edc3", + "9650ee69410c68ec", + "608fe49756dc68cc", + "e7bfc160fd3c0d5d", + "335800e03030fb93", + "446aa68e0c4c5083", + "1e58fd6b31d72e2a", + "4c1ccde478ce063a", + "5cc6ace5ef0d7525", + "09b17cb9b3c8b1bb", + "bbf0ceb1e0e4c6ee", + "c78ba3edcbd57788", + "ead1076787fdd7e4", + "8ecc2cf269498bee", + "d6d6b7c041820ab8", + "d837b4fde544a9f2", + "3ef6d59aeaa6d26e", + "fca2af05ee78ac5c", + "cf5cfcae47e5e3a1", + "baa8b8c5f52810af", + "3f45ee333ce457bb", + "7e24a5a087db6814", + "30f71b100c5cebae", + "9a22a2bb323cfd0f", + "84a75b6fc33b669e", + "21d71bac070403e0", + "0d4385899adc0781", + "05726637bd47a762", + "7a9f073396eaec67", + "5cdef03a3004a6ff", + "7d8dc0575933f142", + "890f788a91fc2fa1", + "5682e68143deea61", + "6dc47e3f5d35aedd", + "16bdbde359584f99", + "0bf7a19b22163465", + "bdd16afe92166295", + "9ad46ff913bb805f", + "b07adba37aa1b7e2", + "3cdca4cc05854ade", + "41148b8edaf1106e", + "85054d3f47bee56c", + "aabc3155ba9aec95", + "dbaf9789160ca414", + "463ecd64b7506048", + "cef1c9957f4ff612", + "1ee8a6a4d8f26d65", + "a92a031f28de3544", + "c1a87780d88d85d9", + "659f501baa5997da", + "95c69029642bdb41", + "e10d907c64d75e3a", + "4fd2ed9e6088176e", + "1eabf957a9401fab", + "cf8ac5972027dda5", + "623dee827372d496", + "f041e5b526e79ef4", + "0832672073492f50", + "0213bdb5ebb8dc19", + "d49988efd778ca9d", + "c301c38902477230", + "376b8eb06fc0b40a", + "037577fc2019fcfa", + "14e053dfe9057aa8", + "28e70f46ba4394dd", + "b9482c3bd09d03dd", + "d2b0cb5a911b8ef8", + "05a8a84b60a30ceb", + "63d0bacbab451d2d", + "5f3c4c189362c2e5", + "c7d162e62f174cd5", + "1f9f4b843070fc1b", + "850f5b2c312299d5", + "b9d8c4cb5cf8a4d6", + "f6147b5c0a147123", + "3db023c27932ad93", + "42a062fe7f1ab253", + "a904d6cb272e8533", + "e86db251be2c8a60", + "5e5d4b87195388c7", + "9ef6037ebd29a9be", + "242fdec5d0ed5010", + "0bd759633c0ceec6", + "6f8d7a6a1dea6a3a", + "a55ace0305e39654", + "19f06ccd7136a2b4", + "2e2d56abe9dd6e22", + "c385c0ffaa17bd29", + "c38734a9eeea0ff8", + "3897d8d16ba333e8", + "d7467eab308fb4a6", + "4761b0a9b046cc66", + "0ac0120f667a8dcf", + "ed10036ddfbda912", + "00efeb17bcaafce6", + "61bff064f593ecc0", + "c3549567b1ad7bdf", + "371dca18821f7714", + "a6cdbfd0a7bef417", + "c175537338906951", + "c7f6cb518fb19151", + "6291bcc06184d125", + "06e505abb8dad1b8", + "82b7b915b7af9c17", + "725b6b95cd47b601", + "4bede5d2af4cb11f", + "600e2a1d0f05afd9", + "03281d5d8a77be56", + "27b4366a0f1fcdef", + "42799014c183e1b3", + "9c6440ecec046cc0", + "b26c9f300c14239d", + "366786e98797ebf3", + "454f266801ae2ae0", + "fdbbd2b53cb2e1e3", + "76610bf4610246c7", + "09963e79b21cde12", + "457fcec1ad31841f", + "6962629b904be54d", + "a7d6e1aeb5e009f0", + "2674228d88c4f3d6", + "2bb4685a03857b2c", + "4d776db86abecdda", + "21c3236216f620ff", + "5a12431e371f3ce9", + "2d2ce200fea72359", + "9aa4b513807ea22c", + "4526aa14337a2b0c", + "f659401e91439524", + "dbbf02a1cd0ad33b" +]
\ No newline at end of file diff --git a/data/reference_annotations_split/valid.json b/data/reference_annotations_split/valid.json new file mode 100644 index 00000000..939924f0 --- /dev/null +++ b/data/reference_annotations_split/valid.json @@ -0,0 +1,312 @@ +[ + "84d6a370e4f38ddc", + "7482381a8f5cf6b8", + "d5074e4b714ac9e7", + "d11406732e3bea76", + "b865bde82d06ebb3", + "e56a494dd7eca1bd", + "0bae4647efd39e51", + "81273108dd167b98", + "85328590c0d7273f", + "dd000f356b48904d", + "e35db152221bc857", + "d44641bd5ae5278f", + "5bf14a907f9a4c65", + "32d4bf275131aa15", + "78bb780793fbb176", + "e5f9f083c2d03d82", + "7623950728f52a71", + "625b243397001f01", + "59f7dd56d9e1b0a8", + "16abf8ee0697e64f", + "66faa094a9333d1a", + "97cc58c1e41f99b0", + "5f3c9c6bf76ba72d", + "0041baf85c9ca3ec", + "ab4814d2b8c742a0", + "a21d17fd2d8b8edc", + "26351f87a8ee7708", + "4b3f577896c80f8a", + "d96438a7165e5d82", + "50aef770cb4f028f", + "4ea21dc6d8ed8838", + "1d800e909e6141d4", + "f817fca54b13831d", + "22388445fe620ac0", + "f6a89befd13a643f", + "0372b733c28f305a", + "3f2a6d4893c18634", + "350581534e265186", + "88902efe4a3194b0", + "63c1045055ec3b58", + "dbefd21e0104bf7c", + "67c8e242329ba986", + "4d983357fd464bb5", + "340a7fd84bf76abf", + "d314fa7ee445bd1d", + "fd1a78c4cfc3ce73", + "0ea6796582fa5732", + "4489bfc781a82281", + "8927428c96c0b59a", + "cf103f7882a05deb", + "b19a4e8667817aa3", + "7f29aa0291e79ae3", + "7e58bfc14edf68e4", + "d472c3dfb2f2a810", + "c2dc665e589f3592", + "83bc5fbf2b54e83b", + "73a8da91bc0e9ef3", + "f419a1217eb38de5", + "7f776a2d7992cecd", + "c3d0eacd0639efb5", + "83e9484cfd868dd3", + "833ff87d69cff5db", + "60dad220f2ab3639", + "b402cb61be362e5f", + "19c7a1b1a2df87d7", + "a17918ec81a36da6", + "120a49c0aa284f68", + "c18fea56107696a8", + "37a37d1a4986527a", + "234da54efbcf734b", + "459539da9315ccac", + "646d03428a882c1b", + "682ae6d18001b529", + "8c92d4b773f61ca8", + "a6fac58198296194", + "2f0be9733140e2c6", + "edb3056f1838e6ae", + "fc875e0381a28435", + "647d17d44745a532", + "2fb4fdf2a570c366", + "b1ef468658a9a0c1", + "cb20c04ba174a26c", + "629372a8091eafae", + "2f43fe24bd8e91e1", + "c1d88ce9dadd7d2d", + "2f3c913f6a97964d", + "8928e191ee2fd3b9", + "f6934fa14d46e748", + "36b156f7888a84cf", + "afa1af9f34e28040", + "60f347ddb0b38299", + "c7c1215819127a1c", + "ee0a5dc41c7621a8", + "3e077f85d5a6c833", + "b00bb452e7a8176c", + "425f13fb7e94add5", + "8e93586c1ec97514", + "1681e7b35fd0cbf9", + "0fe8df0e85116b61", + "b88f4271f7200c7d", + "be874afd46c1e39a", + "bcac7e3f9f614ec6", + "ce504241f1c04e66", + "9664c0f0ec6401b9", + "92f3743c5ec7a199", + "994ac7d986a99e50", + "96d69242a699323d", + "a5adb726852f5cc5", + "82c717a9a379b75c", + "03fad65e5af65088", + "c63e878cc60a8682", + "2c2244c35d126bfb", + "5a5aa275eb4ec7b5", + "69b15e884cc13c70", + "ec1d79d2314e86c1", + "861434b03ddcac64", + "f5035bed07944920", + "37bae9eaf342542b", + "0dc53ac916660b90", + "a0c38b4389ad7cf7", + "f00a01940be6481d", + "fcfd47d66ec6e37d", + "3cb89a7fc7672364", + "28c5a30fd4464675", + "b3b547454a63153b", + "c37a9b7ae53093d8", + "a7840a951b1de6c2", + "e1b08870ad5117a8", + "798f2870a2d9dcd0", + "bcd8763845d1b292", + "81cbadb9d7a6993c", + "d77bee5cc3a0378d", + "c23bb542201aa511", + "f4d510a39278e687", + "293d35fb3749487b", + "0eefe40a0baa2971", + "0767ea7f695f5166", + "720aab4f782f4c60", + "610581cb76d7590d", + "928a4c5185e10dbd", + "8424207a5053802b", + "3fb4f28492730d2e", + "1e23ae421d7a2d01", + "01bb9c4c07d29bff", + "b8875373ee66e841", + "7537ed41507e461b", + "8d89e926a34fee1b", + "db7627e56b8621b1", + "92aa6b2fcbfc7722", + "d3b779682ee988c8", + "611a1cc1a2d405d3", + "3a3ae16e94bc7aba", + "f654c82bca57cf62", + "2b1f098200b44adf", + "8d4a6cefea9d8f17", + "f357d2d64485b9c9", + "9f0de9801a38d664", + "7ce2c3dbaa47508a", + "0e22fe4e4e58faf4", + "0694786160024e30", + "0f53257eb74bee54", + "94fb86d31446e531", + "031667f4e242da61", + "d696a9daccdb2a9f", + "4c017087976d05eb", + "8037b4b4bc8d26c2", + "73e0b884cd04d9bc", + "c46a9d4c505a95d1", + "13c393fa406a72cb", + "89a05fc32f2f5834", + "d4a83d8a8bd26bab", + "fbc78e2407910a4b", + "37411c359cd8cc6c", + "4ef66341677f73f5", + "48fbeab82953a1e8", + "43109d44111df5d3", + "cfffcf0b8f0516a5", + "cefb1202ed3cd997", + "e0a244a6765fd08f", + "5926a9aa89511b26", + "59ecc4b560f48ba8", + "559b3c20886ed742", + "c8cc75b95f0c8047", + "1e7b90184a127017", + "2d835bff00514238", + "e76ba28e58604c26", + "2cbc543a7c7de8b5", + "aabd0ff0d82fff72", + "37c937488a4647a8", + "5a7c1a87df0e05ed", + "657f8d0cc39bbcdc", + "1816ddecd7432cf9", + "bad93fb821395db2", + "0bb56716a1fbef1e", + "ef9e2e35160ff85e", + "a6dc46792d4e41c8", + "238f8edc5eda1358", + "3357c28c91cc2ed1", + "f05de4db911ec8af", + "c55f7ae8ec2a2b95", + "21f23f5e8c270deb", + "265e576fd3517f91", + "1a27e38bd8df6232", + "cb1947cca068e463", + "c030c8ed94582dce", + "46c90dce23083cfe", + "d185510cb8fd18f9", + "9d69024aca1c4854", + "0d2cab8061464438", + "141b99fabc179550", + "74ceffa7e539fa48", + "6ed3cd21c6a2c9d0", + "dc45c7a6ef17f8b5", + "f0d94de8beabbd84", + "5d13cfce75a45cd1", + "38e7d62918a4f9b6", + "d7c8920acdf478ea", + "1b71508a0007113e", + "077c28a0185d07ab", + "b1f2aa8f6f76b30c", + "8dd850c81b49a1f9", + "09c97bb07b943fc5", + "844703f5c2809777", + "5e731c2ba80088f0", + "2748f920f4df8eaf", + "35482ae218713d54", + "87286bdc06061018", + "0c7ef6c32cbdee47", + "537154d2c4344d48", + "187d237ce11c036e", + "f96206c3f5234d23", + "edfe491576c461c4", + "4edd58bd918ce969", + "fe55e99f4f3dc195", + "6a85bb1d21a35e7d", + "774cb0f28f7900f9", + "df9ccdffca7c28c8", + "f48b3738091c9424", + "b664311c69cff92d", + "22d6578b30f5a227", + "1657515edd068cd6", + "710c8d7f75c0a710", + "4d38305c4a2ee035", + "cae968d4926648bd", + "dc562be6acc8930e", + "d211465bc603f6af", + "0efe2627f1ce8ac2", + "8da263e23f332322", + "bbc41d7d09e40c0c", + "9c662ed62bfd5d2b", + "48e6abb1bafdff36", + "34de7910ace6d2e9", + "e6057ffc5085a192", + "adca05bec28db483", + "011796336c7b94de", + "1754df1f2e3d5adb", + "ef339ad918652d91", + "4fa8af0edccb7ada", + "8532a6232360aff8", + "6d1d34e4c80a3368", + "3983cd9d80386fb4", + "d55eb8c97d71e843", + "000176284683faa2", + "328058c83791df93", + "ebc77980250ee68f", + "cc533c087f06ad0d", + "7b1efef5807fbf94", + "a3c99646acb0bb6f", + "f6317f134f532696", + "67a79bfc84b4071b", + "d7e408fcb899dade", + "8344cee00da693fb", + "fb6b381d9ec012fd", + "bbcfe0aee7ea78ea", + "5dd0014fd38a553d", + "2793414918738c7f", + "983d16512ae92d46", + "1a5f86cb1d942c37", + "991790f44a825778", + "7a12bbde6a73c9af", + "1e545ff455f7ea5d", + "0d94556c4f9d05ad", + "0b36924a005c2ae2", + "6785be05d030779b", + "5140d3b40ac28386", + "7941d384f7b9cde1", + "a67614bd685d7dfc", + "24de96ea505af909", + "38f79f1a48e7844f", + "c24f7253b10c0356", + "13da66c1d4719bbb", + "5c06e4fb1887fdc7", + "2532fe8c7214c485", + "4962c0d8106b8b5e", + "4ef5adf3069403e9", + "e9ed6f2d52911d5c", + "fd34fcd8a64e1253", + "eea7fe4f5d754792", + "a4bbf07046109fc9", + "29964f32c68b0ce8", + "078becead8a70053", + "d0055474970a4f5c", + "24363a67840112f4", + "0656984a0d34dbdd", + "e3b6fe6756441ee1", + "1b20b1629ba7d3a6", + "5cf51622fafaf868", + "ba69597434946260", + "2fdab67916d89c9b", + "14b5a3a574c90154" +]
\ No newline at end of file diff --git a/docs/_static/logo.png b/docs/_static/logo.png Binary files differnew file mode 100644 index 00000000..3667dcf6 --- /dev/null +++ b/docs/_static/logo.png diff --git a/docs/_static/logo_badge.png b/docs/_static/logo_badge.png Binary files differnew file mode 100644 index 00000000..de2ea153 --- /dev/null +++ b/docs/_static/logo_badge.png diff --git a/docs/_static/logolink_OP_VVV_hor_barva_eng.jpg b/docs/_static/logolink_OP_VVV_hor_barva_eng.jpg Binary files differnew file mode 100644 index 00000000..fdbb9ea6 --- /dev/null +++ b/docs/_static/logolink_OP_VVV_hor_barva_eng.jpg diff --git a/docs/conf.py b/docs/conf.py index 996e8521..562491f9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -18,7 +18,7 @@ from importlib.metadata import version as get_version # -- Project information ----------------------------------------------------- project = "sec-certs" -copyright = "2020-2022" +copyright = "CRoCS MUNI | 2020-2023" # Note thas this inference won't work from Docker: https://github.com/pypa/setuptools_scm/#usage-from-docker release = ".".join(get_version("sec-certs").split(".")[:3]) @@ -59,11 +59,11 @@ html_theme = "sphinx_book_theme" # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ["_static"] -html_logo = "_static/logo.svg" -html_favicon = "_static/logo_badge.svg" +html_logo = "_static/logo.png" +html_favicon = "_static/logo_badge.png" html_theme_options = { - "repository_url": "https://anonymous.4open.science/r/sec-certs-7A92", + "repository_url": "https://github.com/crocs-muni/sec-certs", "repository_branch": "main", "launch_buttons": {"binderhub_url": "https://mybinder.org"}, "use_fullscreen_button": False, diff --git a/docs/index.md b/docs/index.md index 0b0ba966..1baac8e6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,10 +1,5 @@ # Sec-certs documentation -```{warning} -This documentation was anonymized but may still contain occasional links back to the non-anonymous GitHub repository. -``` - - Welcome to the technical documentation of *sec-certs* tool for the data analysis of products certified with Common Criteria or FIPS 140 frameworks. If you're looking for general description of the tool, its use cases and capabilites, we refer you to [sec-certs homepage](https://seccerts.org/). If you are looking for more advanced knowledge, e.g. how to mine your own data, how to extend the tool, and so forth, this is the right place. There are three main parts of this documentation. *User's guide* describes high-level use of our tool. Driven by this knowledge, you can progress to *Notebook examples* that showcase some of the API that we use in the form of Jupyter notebooks. The documentation also contains some of the modules documented with `autodoc`, see *API reference*. Still, some dark corners of our codebase are not documented. To inspect the code directly, see the [sec_certs](https://github.com/crocs-muni/sec-certs/tree/main/src/sec_certs) module. If you want, you can run the notebooks as they are stored in the [project repository](https://github.com/crocs-muni/sec-certs/tree/main/notebooks). If you are interested in contributing to our project or in other aspects of our development, you can consult the relevant *GitHub artifacts* @@ -26,7 +21,7 @@ Each of the notebooks can be launched interactively in MyBinder by clicking on ð :maxdepth: 1 Seccerts homepage <https://seccerts.org/> Seccerts docs <https://seccerts.org/docs> -GitHub repo <https://anonymous.4open.science/r/sec-certs-7A92/> +GitHub repo <https://github.com/crocs-muni/sec-certs> Seccerts PyPi <https://pypi.org/project/sec-certs/> ``` diff --git a/notebooks/cc/reference_annotations/train_validation_test_split.ipynb b/notebooks/cc/reference_annotations/train_validation_test_split.ipynb new file mode 100644 index 00000000..840adb46 --- /dev/null +++ b/notebooks/cc/reference_annotations/train_validation_test_split.ipynb @@ -0,0 +1,81 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from sec_certs.dataset import CCDataset\n", + "from sec_certs.sample import CCCertificate\n", + "import pandas as pd\n", + "from sklearn.model_selection import train_test_split\n", + "import json" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "dset = CCDataset.from_web_latest()\n", + "df = dset.to_pandas()\n", + "reference_rich_certs = {x.dgst for x in dset if (x.heuristics.st_references.directly_referencing and x.state.st_txt_path) or (x.heuristics.report_references.directly_referencing and x.state.report_txt_path)}\n", + "df = df.loc[df.index.isin(reference_rich_certs)]\n", + "\n", + "# The following certs go straight to the test set as they represent super rare categories that we cannot split\n", + "certs_from_rare_categories = df.loc[df.category.isin({\"Multi-Function Devices\", \"Mobility\", \"Data Protection\"})].index.tolist()\n", + "df = df.loc[~df.index.isin(certs_from_rare_categories)]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# This splits 30/20/50 (train, valid, test)\n", + "x_train, x_test = train_test_split(df.index, test_size=0.5, shuffle=True, stratify=df.category)\n", + "x_train, x_valid = train_test_split(x_train, test_size=0.4, shuffle=True, stratify=df.loc[df.index.isin(x_train)].category)\n", + "x_test = list(x_test) + list(certs_from_rare_categories)\n", + "\n", + "with open(\"../../../data/reference_annotations_split/train.json\", \"w\") as handle:\n", + " json.dump(x_train.tolist(), handle, indent=4)\n", + "\n", + "with open(\"../../../data/reference_annotations_split/valid.json\", \"w\") as handle:\n", + " json.dump(x_valid.tolist(), handle, indent=4)\n", + "\n", + "with open(\"../../../data/reference_annotations_split/test.json\", \"w\") as handle:\n", + " json.dump(x_test, handle, indent=4) " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "a5b8c5b127d2cfe5bc3a1c933e197485eb9eba25154c3661362401503b4ef9d4" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/pyproject.toml b/pyproject.toml index 5948f79a..0c7f33d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ "pdftotext", "pikepdf", "Pillow>=9.2.0", - "PyPDF2", + "pypdf[crypto]>=3.1.0", "python-dateutil", "PyYAML", "rapidfuzz", @@ -62,7 +62,9 @@ [project.optional-dependencies] dev = [ - "mypy", + "black==23.1.0", + "ruff==0.0.239", + "mypy==1.0.0", "types-PyYAML", "types-python-dateutil", "types-requests", @@ -70,9 +72,6 @@ "pytest-cov", "pytest-monitor", "pytest-profiling", - "black", - "isort", - "flake8", "pre-commit", "pip-tools", "sphinx", @@ -80,8 +79,6 @@ "sphinx-book-theme", "sphinx-design", "sphinx-copybutton", - "pyupgrade", - "flake8-future-annotations", "ipython!=8.7.0", ] test = ["pytest", "coverage", "pytest-cov"] @@ -94,8 +91,30 @@ [project.scripts] sec-certs = "sec_certs.cli:main" -[tool.setuptools.package-data] - "*" = ["*.yaml", "*.json"] +[tool.ruff] + select = [ + "I", # isort + "E", # pycodestyle + "W", # pycodestyle + "F", # pyflakes + "C90", # mccabe + "UP", # pyupgrade + "PTH", # enforce pathlib usage + "C4", # comprehensions + "SIM", + ] + ignore = [ + "E501", # line-length, should be handled by black + ] + src = ["src", "tests"] + line-length = 120 + target-version = "py38" + + [tool.ruff.mccabe] + max-complexity = 10 + + [tool.setuptools.package-data] + "*" = ["*.yaml", "*.json"] [tool.setuptools_scm] @@ -104,31 +123,24 @@ [tool.black] line-length = 120 - exclude = ''' + force-exclude = ''' /( \.git | \.mypy_cache | \.tox | venv - | certsvenv | \.venv | _build | buck-out | build | dist | src/sec_certs/_version.py + | docs + | .ipynb_checkpoints + | .eggs )/ ''' -[tool.isort] - multi_line_output = 3 - include_trailing_comma = true - force_grid_wrap = 0 - use_parentheses = true - ensure_newline_before_comments = true - line_length = 120 - skip = ["certsvenv", "build"] - [tool.mypy] plugins = ["numpy.typing.mypy_plugin"] ignore_missing_imports = true diff --git a/requirements/dev_requirements.txt b/requirements/dev_requirements.txt index e174d11b..a44ecdba 100644 --- a/requirements/dev_requirements.txt +++ b/requirements/dev_requirements.txt @@ -21,7 +21,7 @@ beautifulsoup4==4.11.1 # sec-certs (./../pyproject.toml) billiard==4.0.2 # via sec-certs (./../pyproject.toml) -black==22.10.0 +black==23.1.0 # via sec-certs (./../pyproject.toml) blis==0.7.9 # via thinc @@ -75,8 +75,6 @@ docutils==0.17.1 # myst-parser # pydata-sphinx-theme # sphinx -en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.4.1/en_core_web_sm-3.4.1.tar.gz - # via sec-certs (./../pyproject.toml) entrypoints==0.4 # via jupyter-client exceptiongroup==1.0.4 @@ -87,12 +85,6 @@ fastjsonschema==2.16.2 # via nbformat filelock==3.8.2 # via virtualenv -flake8==6.0.0 - # via - # flake8-future-annotations - # sec-certs (./../pyproject.toml) -flake8-future-annotations==1.0.0 - # via sec-certs (./../pyproject.toml) fonttools==4.38.0 # via matplotlib gprof2dot==2022.7.29 @@ -121,7 +113,7 @@ ipykernel==6.19.1 # ipywidgets # myst-nb # sec-certs (./../pyproject.toml) -ipython==8.6.0 +ipython==8.10.0 # via # ipykernel # ipywidgets @@ -129,8 +121,6 @@ ipython==8.6.0 # sec-certs (./../pyproject.toml) ipywidgets==8.0.3 # via sec-certs (./../pyproject.toml) -isort==5.10.1 - # via sec-certs (./../pyproject.toml) jedi==0.18.2 # via ipython jinja2==3.1.2 @@ -179,8 +169,6 @@ matplotlib-inline==0.1.6 # via # ipykernel # ipython -mccabe==0.7.0 - # via flake8 mdit-py-plugins==0.3.3 # via myst-parser mdurl==0.1.2 @@ -192,7 +180,7 @@ murmurhash==1.0.9 # preshed # spacy # thinc -mypy==0.991 +mypy==1.0.0 # via sec-certs (./../pyproject.toml) mypy-extensions==0.4.3 # via @@ -236,6 +224,7 @@ numpy==1.23.5 # thinc packaging==22.0 # via + # black # build # deprecation # ipykernel @@ -303,8 +292,8 @@ ptyprocess==0.7.0 # via pexpect pure-eval==0.2.2 # via stack-data -pycodestyle==2.10.0 - # via flake8 +pycryptodome==3.16.0 + # via pypdf pydantic==1.10.2 # via # confection @@ -312,15 +301,13 @@ pydantic==1.10.2 # thinc pydata-sphinx-theme==0.8.1 # via sphinx-book-theme -pyflakes==3.0.1 - # via flake8 pygments==2.13.0 # via # ipython # sphinx pyparsing==3.0.9 # via matplotlib -pypdf2==2.11.2 +pypdf[crypto]==3.2.1 # via sec-certs (./../pyproject.toml) pyrsistent==0.19.2 # via jsonschema @@ -348,8 +335,6 @@ pytz==2022.6 # via # babel # pandas -pyupgrade==3.3.1 - # via sec-certs (./../pyproject.toml) pyyaml==6.0 # via # jupyter-cache @@ -370,6 +355,8 @@ requests==2.28.1 # sec-certs (./../pyproject.toml) # spacy # sphinx +ruff==0.0.239 + # via sec-certs (./../pyproject.toml) scikit-learn==1.2.0 # via sec-certs (./../pyproject.toml) scipy==1.9.3 @@ -395,9 +382,7 @@ snowballstemmer==2.2.0 soupsieve==2.3.2.post1 # via beautifulsoup4 spacy==3.4.3 - # via - # en-core-web-sm - # sec-certs (./../pyproject.toml) + # via sec-certs (./../pyproject.toml) spacy-legacy==3.0.10 # via spacy spacy-loggers==1.0.4 @@ -446,8 +431,6 @@ thinc==8.1.5 # via spacy threadpoolctl==3.1.0 # via scikit-learn -tokenize-rt==5.0.0 - # via pyupgrade toml==0.10.2 # via pre-commit tomli==2.0.1 @@ -492,11 +475,12 @@ types-urllib3==1.26.25.4 # via types-requests typing-extensions==4.4.0 # via + # black # mypy # myst-nb # myst-parser # pydantic - # pypdf2 + # pypdf # setuptools-scm urllib3==1.26.13 # via requests diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 91411c35..67d80236 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -48,8 +48,6 @@ deprecation==2.1.0 # via pikepdf distro==1.8.0 # via tabula-py -en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.4.1/en_core_web_sm-3.4.1.tar.gz - # via sec-certs (./../pyproject.toml) entrypoints==0.4 # via jupyter-client executing==1.2.0 @@ -66,7 +64,7 @@ ipykernel==6.19.1 # via # ipywidgets # sec-certs (./../pyproject.toml) -ipython==8.7.0 +ipython==8.10.0 # via # ipykernel # ipywidgets @@ -179,6 +177,8 @@ ptyprocess==0.7.0 # via pexpect pure-eval==0.2.2 # via stack-data +pycryptodome==3.16.0 + # via pypdf pydantic==1.10.2 # via # confection @@ -188,7 +188,7 @@ pygments==2.13.0 # via ipython pyparsing==3.0.9 # via matplotlib -pypdf2==2.11.2 +pypdf[crypto]==3.2.1 # via sec-certs (./../pyproject.toml) pyrsistent==0.19.2 # via jsonschema @@ -236,9 +236,7 @@ smart-open==6.2.0 soupsieve==2.3.2.post1 # via beautifulsoup4 spacy==3.4.3 - # via - # en-core-web-sm - # sec-certs (./../pyproject.toml) + # via sec-certs (./../pyproject.toml) spacy-legacy==3.0.10 # via spacy spacy-loggers==1.0.4 @@ -282,7 +280,7 @@ typer==0.7.0 typing-extensions==4.4.0 # via # pydantic - # pypdf2 + # pypdf # setuptools-scm urllib3==1.26.13 # via requests diff --git a/requirements/test_requirements.txt b/requirements/test_requirements.txt index f60c03ca..43373faf 100644 --- a/requirements/test_requirements.txt +++ b/requirements/test_requirements.txt @@ -54,8 +54,6 @@ deprecation==2.1.0 # via pikepdf distro==1.8.0 # via tabula-py -en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.4.1/en_core_web_sm-3.4.1.tar.gz - # via sec-certs (./../pyproject.toml) entrypoints==0.4 # via jupyter-client exceptiongroup==1.0.4 @@ -76,7 +74,7 @@ ipykernel==6.19.1 # via # ipywidgets # sec-certs (./../pyproject.toml) -ipython==8.7.0 +ipython==8.10.0 # via # ipykernel # ipywidgets @@ -192,6 +190,8 @@ ptyprocess==0.7.0 # via pexpect pure-eval==0.2.2 # via stack-data +pycryptodome==3.16.0 + # via pypdf pydantic==1.10.2 # via # confection @@ -201,7 +201,7 @@ pygments==2.13.0 # via ipython pyparsing==3.0.9 # via matplotlib -pypdf2==2.11.2 +pypdf[crypto]==3.2.1 # via sec-certs (./../pyproject.toml) pyrsistent==0.19.2 # via jsonschema @@ -255,9 +255,7 @@ smart-open==6.2.0 soupsieve==2.3.2.post1 # via beautifulsoup4 spacy==3.4.3 - # via - # en-core-web-sm - # sec-certs (./../pyproject.toml) + # via sec-certs (./../pyproject.toml) spacy-legacy==3.0.10 # via spacy spacy-loggers==1.0.4 @@ -304,7 +302,7 @@ typer==0.7.0 typing-extensions==4.4.0 # via # pydantic - # pypdf2 + # pypdf # setuptools-scm urllib3==1.26.13 # via requests diff --git a/src/sec_certs/cert_rules.py b/src/sec_certs/cert_rules.py index 145566f7..c126434b 100644 --- a/src/sec_certs/cert_rules.py +++ b/src/sec_certs/cert_rules.py @@ -205,21 +205,19 @@ def _load(): script_dir = Path(__file__).parent filepath = script_dir / "rules.yaml" with Path(filepath).open("r") as file: - loaded = yaml.load(file, Loader=yaml.FullLoader) - return loaded + return yaml.load(file, Loader=yaml.FullLoader) -def _process(obj): +def _process(obj: dict | list): if isinstance(obj, dict): return {k: _process(v) for k, v in obj.items()} - elif isinstance(obj, list): - return [ - re.compile( - REGEXEC_SEP_START + MATCH_START + rule + MATCH_END + REGEXEC_SEP_END, - re.MULTILINE, - ) - for rule in obj - ] + return [ + re.compile( + REGEXEC_SEP_START + MATCH_START + rule + MATCH_END + REGEXEC_SEP_END, + re.MULTILINE, + ) + for rule in obj + ] rules = _load() diff --git a/src/sec_certs/cli.py b/src/sec_certs/cli.py index a25b55ee..08ef6abd 100644 --- a/src/sec_certs/cli.py +++ b/src/sec_certs/cli.py @@ -10,9 +10,9 @@ from typing import Callable import click -from sec_certs import constants from sec_certs.config.configuration import config from sec_certs.dataset import CCDataset, FIPSDataset +from sec_certs.dataset.dataset import Dataset from sec_certs.utils.helpers import warn_if_missing_poppler, warn_if_missing_tesseract logger = logging.getLogger(__name__) @@ -20,6 +20,8 @@ logger = logging.getLogger(__name__) EXIT_CODE_NOK: int = 1 EXIT_CODE_OK: int = 0 +DEFAULT_OUTPUTPATH: Path = Path("./dataset").resolve() + @dataclass class ProcessingStep: @@ -29,6 +31,11 @@ class ProcessingStep: precondition_error_msg: str | None = field(default=None) pre_callback_func: Callable | None = field(default=None) + def __post_init__(self) -> None: + for condition in self.preconditions: + if not hasattr(Dataset.DatasetInternalState, condition): + raise ValueError(f"Precondition attribute {condition} is not member of `Dataset.DatasetInternalState`.") + def run(self, dset: CCDataset | FIPSDataset) -> None: for condition in self.preconditions: if not getattr(dset.state, condition): @@ -54,12 +61,14 @@ def build_or_load_dataset( framework: str, inputpath: Path | None, to_build: bool, - outputpath: Path = constants.DUMMY_NONEXISTING_PATH, + outputpath: Path | None, ) -> CCDataset | FIPSDataset: constructor: type[CCDataset] | type[FIPSDataset] = CCDataset if framework == "cc" else FIPSDataset dset: CCDataset | FIPSDataset if to_build: + if not outputpath: + outputpath = DEFAULT_OUTPUTPATH if inputpath: print( f"Warning: you wanted to build a dataset but you provided one in JSON -- that will be ignored. New one will be constructed at: {outputpath}" @@ -72,23 +81,56 @@ def build_or_load_dataset( ) dset.get_certs_from_web() else: - if inputpath: - dset = constructor.from_json(inputpath) - if outputpath and dset.root_dir != outputpath: - print( - "Warning: you provided both input and output paths. The dataset from input path will get copied to output path." - ) - dset.copy_dataset(outputpath) - else: + if not inputpath: click.echo( "Error: If you do not use 'build' action, you must provide --input parameter to point to an existing dataset.", err=True, ) sys.exit(EXIT_CODE_NOK) + dset = constructor.from_json(inputpath) + + if outputpath and dset.root_dir != outputpath: + print( + "Warning: you provided both input and output paths. The dataset from input path will get copied to output path." + ) + dset.copy_dataset(outputpath) + return dset +steps = [ + ProcessingStep( + "process-aux-dsets", + "process_auxiliary_datasets", + preconditions=["meta_sources_parsed"], + precondition_error_msg="Error: You want to process the auxiliary datasets, but the data from cert. framework website was not parsed. You must use 'build' action first.", + pre_callback_func=None, + ), + ProcessingStep( + "download", + "download_all_artifacts", + preconditions=["meta_sources_parsed"], + precondition_error_msg="Error: You want to download all artifacts, but the data from the cert. framework website was not parsed. You must use 'build' action first.", + pre_callback_func=None, + ), + ProcessingStep( + "convert", + "convert_all_pdfs", + preconditions=["artifacts_downloaded"], + precondition_error_msg="Error: You want to convert pdfs -> txt, but the pdfs were not downloaded. You must use 'download' action first.", + pre_callback_func=warn_missing_libs, + ), + ProcessingStep( + "analyze", + "analyze_certificates", + preconditions=["pdfs_converted", "auxiliary_datasets_processed"], + precondition_error_msg="Error: You want to process txt documents of certificates, but pdfs were not converted. You must use 'convert' action first.", + pre_callback_func=None, + ), +] + + @click.command() @click.argument( "framework", @@ -105,10 +147,9 @@ def build_or_load_dataset( @click.option( "-o", "--output", + "outputpath", type=click.Path(file_okay=False, dir_okay=True, writable=True, readable=True, resolve_path=True), help="Path where the output of the experiment will be stored. May overwrite existing content.", - default=Path("./dataset/"), - show_default=True, ) @click.option( "-c", @@ -129,10 +170,10 @@ def build_or_load_dataset( def main( framework: str, actions: list[str], - outputpath: Path, - configpath: str | None, + outputpath: Path | None, + configpath: Path | None, inputpath: Path | None, - silent: bool, + quiet: bool, ): try: file_handler = logging.FileHandler(config.log_filepath) @@ -140,13 +181,13 @@ def main( formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") file_handler.setFormatter(formatter) stream_handler.setFormatter(formatter) - handlers: list[logging.StreamHandler] = [file_handler] if silent else [file_handler, stream_handler] + handlers: list[logging.StreamHandler] = [file_handler] if quiet else [file_handler, stream_handler] logging.basicConfig(level=logging.INFO, handlers=handlers) start = datetime.now() if configpath: try: - config.load(Path(configpath)) + config.load(configpath) except FileNotFoundError: click.echo("Error: Bad path to configuration file", err=True) sys.exit(EXIT_CODE_NOK) @@ -155,54 +196,24 @@ def main( sys.exit(EXIT_CODE_NOK) actions_set = ( - {"build", "process-aux-dsets", "download", "convert", "analyze", "maintenances"} - if "all" in actions - else set(actions) + {"build", "process-aux-dsets", "download", "convert", "analyze"} if "all" in actions else set(actions) ) dset = build_or_load_dataset(framework, inputpath, "build" in actions_set, outputpath) aux_dsets_to_handle = "PP, Maintenance updates" if framework == "cc" else "Algorithms" aux_dsets_to_handle += "CPE, CVE" - analysis_pre_callback = None - - steps = [ - ProcessingStep( - "process-aux-dsets", - "process_auxillary_datasets", - preconditions=["meta_sources_parsed"], - precondition_error_msg=f"Error: You want to process the auxillary datasets: {aux_dsets_to_handle} , but the data from cert. framework website was not parsed. You must use 'build' action first.", - pre_callback_func=None, - ), - ProcessingStep( - "download", - "download_all_artifacts", - preconditions=["meta_sources_parsed"], - precondition_error_msg="Error: You want to download all artifacts, but the data from the cert. framework website was not parsed. You must use 'build' action first.", - pre_callback_func=None, - ), - ProcessingStep( - "convert", - "convert_all_pdfs", - preconditions=["pdfs_downloaded"], - precondition_error_msg="Error: You want to convert pdfs -> txt, but the pdfs were not downloaded. You must use 'download' action first.", - pre_callback_func=warn_missing_libs, - ), - ProcessingStep( - "analyze", - "analyze_certificates", - preconditions=["pdfs_converted", "auxillary_datasets_processed"], - precondition_error_msg="Error: You want to process txt documents of certificates, but pdfs were not converted. You must use 'convert' action first.", - pre_callback_func=analysis_pre_callback, - ), - ] processing_step: ProcessingStep - for processing_step in [x for x in steps if x in actions_set]: + for processing_step in [x for x in steps if x.name in actions_set]: processing_step.run(dset) end = datetime.now() logger.info(f"The computation took {(end-start)} seconds.") - except Exception: + except Exception as e: + click.echo( + f"Unhandled exception: {e}", + err=True, + ) return EXIT_CODE_NOK return EXIT_CODE_OK diff --git a/src/sec_certs/config/settings-schema.json b/src/sec_certs/config/settings-schema.json index a31f6b3f..2d5c17a6 100644 --- a/src/sec_certs/config/settings-schema.json +++ b/src/sec_certs/config/settings-schema.json @@ -96,7 +96,7 @@ { "properties": { "value": { - "minimum": 1 + "minimum": -1 } } } diff --git a/src/sec_certs/config/settings.yaml b/src/sec_certs/config/settings.yaml index 8d645758..c69f7cdf 100644 --- a/src/sec_certs/config/settings.yaml +++ b/src/sec_certs/config/settings.yaml @@ -13,8 +13,8 @@ year_difference_between_validations: difference higher than _this_ value: 7 n_threads: - description: How many threads to use for parallel computations - value: 8 + description: How many threads to use for parallel computations. Set to -1 to use all cores (*2 with multithreading). + value: -1 cpe_matching_threshold: description: Level of required string similarity between CPE and certificate name on CC CPE matching, 0-100. Lower values yield more false negatives, higher values more false positives value: 92 diff --git a/src/sec_certs/constants.py b/src/sec_certs/constants.py index f71bb3c3..684662d0 100644 --- a/src/sec_certs/constants.py +++ b/src/sec_certs/constants.py @@ -74,7 +74,10 @@ CC_CANADA_INEVAL_URL = "https://www.cyber.gc.ca/en/tools-services/common-criteri CC_ANSSI_BASE_URL = "https://www.ssi.gouv.fr" CC_ANSSI_CERTIFIED_URL = CC_ANSSI_BASE_URL + "/en/products/certified-products/" CC_BSI_BASE_URL = "https://www.bsi.bund.de/" -CC_BSI_CERTIFIED_URL = CC_BSI_BASE_URL + "EN2021/Topics/Certification/certified_products/certified_products_node.html" +CC_BSI_CERTIFIED_URL = ( + CC_BSI_BASE_URL + + "EN/Themen/Unternehmen-und-Organisationen/Standards-und-Zertifizierung/Zertifizierung-und-Anerkennung/Listen/Zertifizierte-Produkte-nach-CC/zertifizierte-produkte-nach-cc_node.html" +) CC_INDIA_CERTIFIED_URL = "https://www.commoncriteria-india.gov.in/product-certified" CC_INDIA_ARCHIVED_URL = "https://www.commoncriteria-india.gov.in/archived-prod-cer" CC_ITALY_BASE_URL = "https://www.ocsi.gov.it" diff --git a/src/sec_certs/dataset/__init__.py b/src/sec_certs/dataset/__init__.py index d5f93c78..c557c630 100644 --- a/src/sec_certs/dataset/__init__.py +++ b/src/sec_certs/dataset/__init__.py @@ -1,4 +1,4 @@ -"""This package exposes Datasets of various Samples, both primary (Common Criteria, FIPS) and auxillary (CVEs, CPEs, ...)""" +"""This package exposes Datasets of various Samples, both primary (Common Criteria, FIPS) and auxiliary (CVEs, CPEs, ...)""" from sec_certs.dataset.cc import CCDataset, CCDatasetMaintenanceUpdates, CCSchemeDataset from sec_certs.dataset.cpe import CPEDataset diff --git a/src/sec_certs/dataset/cc.py b/src/sec_certs/dataset/cc.py index 9894bd48..c2849772 100644 --- a/src/sec_certs/dataset/cc.py +++ b/src/sec_certs/dataset/cc.py @@ -21,7 +21,7 @@ from sec_certs import constants from sec_certs.config.configuration import config from sec_certs.dataset.cpe import CPEDataset from sec_certs.dataset.cve import CVEDataset -from sec_certs.dataset.dataset import AuxillaryDatasets, Dataset, logger +from sec_certs.dataset.dataset import AuxiliaryDatasets, Dataset, logger from sec_certs.dataset.protection_profile import ProtectionProfileDataset from sec_certs.model.reference_finder import ReferenceFinder from sec_certs.model.sar_transformer import SARTransformer @@ -31,20 +31,20 @@ from sec_certs.sample.cc_certificate_id import CertificateId from sec_certs.sample.cc_maintenance_update import CCMaintenanceUpdate from sec_certs.sample.protection_profile import ProtectionProfile from sec_certs.serialization.json import ComplexSerializableType, CustomJSONDecoder, serialize -from sec_certs.utils import helpers as helpers +from sec_certs.utils import helpers from sec_certs.utils import parallel_processing as cert_processing from sec_certs.utils.sanitization import sanitize_navigable_string as sns @dataclass -class CCAuxillaryDatasets(AuxillaryDatasets): +class CCAuxiliaryDatasets(AuxiliaryDatasets): cpe_dset: CPEDataset | None = None cve_dset: CVEDataset | None = None pp_dset: ProtectionProfileDataset | None = None mu_dset: CCDatasetMaintenanceUpdates | None = None -class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializableType): +class CCDataset(Dataset[CCCertificate, CCAuxiliaryDatasets], ComplexSerializableType): """ Class that holds CCCertificate. Serializable into json, pandas, dictionary. Conveys basic certificate manipulations and dataset transformations. Many private methods that perform internal operations, feel free to exploit them. @@ -52,12 +52,12 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable def __init__( self, - certs: dict[str, CCCertificate] = dict(), + certs: dict[str, CCCertificate] = {}, root_dir: str | Path = constants.DUMMY_NONEXISTING_PATH, name: str | None = None, description: str = "", state: Dataset.DatasetInternalState | None = None, - auxillary_datasets: CCAuxillaryDatasets | None = None, + auxiliary_datasets: CCAuxiliaryDatasets | None = None, ): self.certs = certs self.timestamp = datetime.now() @@ -66,8 +66,8 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable self.description = description if description else datetime.now().strftime("%d/%m/%Y %H:%M:%S") self.state = state if state else self.DatasetInternalState() - self.auxillary_datasets: CCAuxillaryDatasets = ( - auxillary_datasets if auxillary_datasets else CCAuxillaryDatasets() + self.auxiliary_datasets: CCAuxiliaryDatasets = ( + auxiliary_datasets if auxiliary_datasets else CCAuxiliaryDatasets() ) self.root_dir = Path(root_dir) @@ -144,14 +144,14 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable """ Returns directory that holds files associated with Protection profiles """ - return self.auxillary_datasets_dir / "pp_dataset.json" + return self.auxiliary_datasets_dir / "pp_dataset.json" @property def mu_dataset_dir(self) -> Path: """ Returns directory that holds dataset of maintenance updates """ - return self.auxillary_datasets_dir / "maintenances" + return self.auxiliary_datasets_dir / "maintenances" @property def mu_dataset_path(self) -> Path: @@ -220,15 +220,15 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable def _set_local_paths(self): super()._set_local_paths() - if self.auxillary_datasets.pp_dset: - self.auxillary_datasets.pp_dset.json_path = self.pp_dataset_path + if self.auxiliary_datasets.pp_dset: + self.auxiliary_datasets.pp_dset.json_path = self.pp_dataset_path - if self.auxillary_datasets.mu_dset: - self.auxillary_datasets.mu_dset.root_dir = self.mu_dataset_dir + if self.auxiliary_datasets.mu_dset: + self.auxiliary_datasets.mu_dset.root_dir = self.mu_dataset_dir for cert in self: cert.set_local_paths(self.reports_pdf_dir, self.targets_pdf_dir, self.reports_txt_dir, self.targets_txt_dir) - # TODO: This forgets to set local paths for other auxillary datasets + # TODO: This forgets to set local paths for other auxiliary datasets def _merge_certs(self, certs: dict[str, CCCertificate], cert_source: str | None = None) -> None: """ @@ -324,13 +324,9 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable return CCDataset.BASE_URL + relative_path def _get_primary_key_str(row: Tag): - prim_key = row["category"] + row["cert_name"] + row["report_link"] - return prim_key + return row["category"] + row["cert_name"] + row["report_link"] - if "active" in str(file): - cert_status = "active" - else: - cert_status = "archived" + cert_status = "active" if "active" in str(file) else "archived" csv_header = [ "category", @@ -394,7 +390,7 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable ) ) - certs = { + return { x.dgst: CCCertificate( cert_status, x.category, @@ -416,7 +412,6 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable ) for x in df_base.itertuples() } - return certs def _get_all_certs_from_html(self, get_active: bool, get_archived: bool) -> dict[str, CCCertificate]: """ @@ -483,10 +478,7 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable return table_certs - if "active" in str(file): - cert_status = "active" - else: - cert_status = "archived" + cert_status = "active" if "active" in str(file) else "archived" cc_cat_abbreviations = ["AC", "BP", "DP", "DB", "DD", "IC", "KM", "MD", "MF", "NS", "OS", "OD", "DG", "TC"] cc_table_ids = ["tbl" + x for x in cc_cat_abbreviations] @@ -535,7 +527,6 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable cert_processing.process_parallel( CCCertificate.download_pdf_report, certs_to_process, - config.n_threads, progress_bar_desc="Downloading PDFs of CC certification reports", ) @@ -553,7 +544,6 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable cert_processing.process_parallel( CCCertificate.download_pdf_st, certs_to_process, - config.n_threads, progress_bar_desc="Downloading PDFs of CC security targets", ) @@ -571,7 +561,6 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable cert_processing.process_parallel( CCCertificate.convert_report_pdf, certs_to_process, - config.n_threads, progress_bar_desc="Converting PDFs of certification reports to txt", ) @@ -589,7 +578,6 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable cert_processing.process_parallel( CCCertificate.convert_st_pdf, certs_to_process, - config.n_threads, progress_bar_desc="Converting PDFs of security targets to txt", ) @@ -603,7 +591,6 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable processed_certs = cert_processing.process_parallel( CCCertificate.extract_report_pdf_metadata, certs_to_process, - config.n_threads, use_threading=False, progress_bar_desc="Extracting report metadata", ) @@ -615,7 +602,6 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable processed_certs = cert_processing.process_parallel( CCCertificate.extract_st_pdf_metadata, certs_to_process, - config.n_threads, use_threading=False, progress_bar_desc="Extracting target metadata", ) @@ -631,7 +617,6 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable processed_certs = cert_processing.process_parallel( CCCertificate.extract_report_pdf_frontpage, certs_to_process, - config.n_threads, use_threading=False, progress_bar_desc="Extracting report frontpages", ) @@ -643,7 +628,6 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable processed_certs = cert_processing.process_parallel( CCCertificate.extract_st_pdf_frontpage, certs_to_process, - config.n_threads, use_threading=False, progress_bar_desc="Extracting target frontpages", ) @@ -659,7 +643,6 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable processed_certs = cert_processing.process_parallel( CCCertificate.extract_report_pdf_keywords, certs_to_process, - config.n_threads, use_threading=False, progress_bar_desc="Extracting report keywords", ) @@ -671,7 +654,6 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable processed_certs = cert_processing.process_parallel( CCCertificate.extract_st_pdf_keywords, certs_to_process, - config.n_threads, use_threading=False, progress_bar_desc="Extracting target keywords", ) @@ -729,7 +711,7 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable return set() res = set() for scheme, matches in kws["cc_cert_id"].items(): - for match in matches.keys(): + for match in matches: try: canonical = CertificateId(scheme, match).canonical res.add(canonical) @@ -750,16 +732,16 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable for dgst in self.certs: setattr(self.certs[dgst].heuristics, dep_attr, finder.predict_single_cert(dgst, keep_unknowns=False)) - def process_auxillary_datasets(self, download_fresh: bool = False) -> None: + @serialize + def process_auxiliary_datasets(self, download_fresh: bool = False) -> None: """ - Processes all auxillary datasets needed during computation. On top of base-class processing, + Processes all auxiliary datasets needed during computation. On top of base-class processing, CC handles protection profiles and maintenance updates. """ - super().process_auxillary_datasets(download_fresh) - self.auxillary_datasets.pp_dset = self.process_protection_profiles(to_download=download_fresh) - self.auxillary_datasets.mu_dset = self.process_maintenance_updates(to_download=download_fresh) + super().process_auxiliary_datasets(download_fresh) + self.auxiliary_datasets.pp_dset = self.process_protection_profiles(to_download=download_fresh) + self.auxiliary_datasets.mu_dset = self.process_maintenance_updates(to_download=download_fresh) - @serialize def process_protection_profiles( self, to_download: bool = True, keep_metadata: bool = True ) -> ProtectionProfileDataset: @@ -773,7 +755,7 @@ class CCDataset(Dataset[CCCertificate, CCAuxillaryDatasets], ComplexSerializable """ logger.info("Processing protection profiles.") - self.auxillary_datasets_dir.mkdir(parents=True, exist_ok=True) + self.auxiliary_datasets_dir.mkdir(parents=True, exist_ok=True) if to_download or not self.pp_dataset_path.exists(): pp_dataset = ProtectionProfileDataset.from_web(self.pp_dataset_path) @@ -829,7 +811,7 @@ class CCDatasetMaintenanceUpdates(CCDataset, ComplexSerializableType): # Quite difficult to achieve correct behaviour with MyPy here, opting for ignore def __init__( self, - certs: dict[str, CCMaintenanceUpdate] = dict(), # type: ignore + certs: dict[str, CCMaintenanceUpdate] = {}, # type: ignore root_dir: Path = constants.DUMMY_NONEXISTING_PATH, name: str = "dataset name", description: str = "dataset_description", @@ -851,7 +833,7 @@ class CCDatasetMaintenanceUpdates(CCDataset, ComplexSerializableType): def compute_related_cves(self) -> None: raise NotImplementedError - def process_auxillary_datasets(self, download_fresh: bool = False) -> None: + def process_auxiliary_datasets(self, download_fresh: bool = False) -> None: raise NotImplementedError def analyze_certificates(self) -> None: @@ -876,9 +858,7 @@ class CCDatasetMaintenanceUpdates(CCDataset, ComplexSerializableType): df.index.name = "dgst" df.maintenance_date = pd.to_datetime(df.maintenance_date, infer_datetime_format=True) - df = df.fillna(value=np.nan) - - return df + return df.fillna(value=np.nan) @classmethod def from_web_latest(cls) -> CCDatasetMaintenanceUpdates: @@ -913,11 +893,8 @@ class CCDatasetMaintenanceUpdates(CCDataset, ComplexSerializableType): class CCSchemeDataset: @staticmethod def _download_page(url, session=None): - if session: - conn = session - else: - conn = requests - resp = conn.get(url, headers={"User-Agent": "seccerts.org"}) + conn = session if session else requests + resp = conn.get(url, headers={"User-Agent": "seccerts.org"}, verify=False) if resp.status_code != requests.codes.ok: raise ValueError(f"Unable to download: status={resp.status_code}") return BeautifulSoup(resp.content, "html5lib") @@ -1056,14 +1033,14 @@ class CCSchemeDataset: pager = soup.find("ul", class_="pager") for li in pager.find_all("li"): try: - new_page = int(li.text) + new_page = int(li.text) - 1 except Exception: continue if new_page not in seen_pages: pages.add(new_page) # Parse table - tbody = soup.find("div", class_="content").find("table").find("tbody") + tbody = soup.find("div", class_="view-content").find("table").find("tbody") for tr in tbody.find_all("tr"): tds = tr.find_all("td") if not tds: @@ -1100,16 +1077,17 @@ class CCSchemeDataset: # Update pages pager = soup.find("ul", class_="pager") - for li in pager.find_all("li"): - try: - new_page = int(li.text) - except Exception: - continue - if new_page not in seen_pages: - pages.add(new_page) + if pager: + for li in pager.find_all("li"): + try: + new_page = int(li.text) - 1 + except Exception: + continue + if new_page not in seen_pages: + pages.add(new_page) # Parse table - tbody = soup.find("div", class_="content").find("table").find("tbody") + tbody = soup.find("div", class_="view-content").find("table").find("tbody") for tr in tbody.find_all("tr"): tds = tr.find_all("td") if not tds: diff --git a/src/sec_certs/dataset/cpe.py b/src/sec_certs/dataset/cpe.py index 927ce674..1a20c71e 100644 --- a/src/sec_certs/dataset/cpe.py +++ b/src/sec_certs/dataset/cpe.py @@ -40,9 +40,9 @@ class CPEDataset(JSONPathDataset, ComplexSerializableType): self.cpes = cpes self.json_path = Path(json_path) - self.vendor_to_versions: dict[str, set[str]] = dict() - self.vendor_version_to_cpe: dict[tuple[str, str], set[CPE]] = dict() - self.title_to_cpes: dict[str, set[CPE]] = dict() + self.vendor_to_versions: dict[str, set[str]] = {} + self.vendor_version_to_cpe: dict[tuple[str, str], set[CPE]] = {} + self.title_to_cpes: dict[str, set[CPE]] = {} self.vendors: set[str] = set() self.build_lookup_dicts() @@ -62,7 +62,7 @@ class CPEDataset(JSONPathDataset, ComplexSerializableType): def __contains__(self, item: CPE) -> bool: if not isinstance(item, CPE): raise ValueError(f"{item} is not of CPE class") - return item.uri in self.cpes.keys() and self.cpes[item.uri] == item + return item.uri in self.cpes and self.cpes[item.uri] == item def __eq__(self, other: object) -> bool: return isinstance(other, CPEDataset) and self.cpes == other.cpes @@ -77,8 +77,8 @@ class CPEDataset(JSONPathDataset, ComplexSerializableType): """ logger.info("CPE dataset: building lookup dictionaries.") self.vendor_to_versions = {x.vendor: set() for x in self} - self.vendor_version_to_cpe = dict() - self.title_to_cpes = dict() + self.vendor_version_to_cpe = {} + self.title_to_cpes = {} self.vendors = set(self.vendor_to_versions.keys()) for cpe in self: self.vendor_to_versions[cpe.vendor].add(cpe.version) @@ -141,9 +141,7 @@ class CPEDataset(JSONPathDataset, ComplexSerializableType): :return pd.DataFrame: the resulting DataFrame """ - df = pd.DataFrame([x.pandas_tuple for x in self], columns=CPE.pandas_columns) - df = df.set_index("uri") - return df + return pd.DataFrame([x.pandas_tuple for x in self], columns=CPE.pandas_columns).set_index("uri") @serialize def enhance_with_cpes_from_cve_dataset(self, cve_dset: CVEDataset | str | Path) -> None: @@ -165,7 +163,7 @@ class CPEDataset(JSONPathDataset, ComplexSerializableType): and (considered_cpe.vendor, considered_cpe.item_name) not in vndr_item_lookup ): return True - elif ( + if ( considered_cpe.version != constants.CPE_VERSION_NA and (considered_cpe.vendor, considered_cpe.item_name, considered_cpe.version) not in vndr_item_version_lookup diff --git a/src/sec_certs/dataset/cve.py b/src/sec_certs/dataset/cve.py index 9a36fa6b..65d141c3 100644 --- a/src/sec_certs/dataset/cve.py +++ b/src/sec_certs/dataset/cve.py @@ -14,13 +14,12 @@ from typing import ClassVar import numpy as np import pandas as pd -import sec_certs.constants as constants -import sec_certs.utils.helpers as helpers -from sec_certs.config.configuration import config +from sec_certs import constants from sec_certs.dataset.json_path_dataset import JSONPathDataset from sec_certs.sample.cpe import CPE, cached_cpe from sec_certs.sample.cve import CVE from sec_certs.serialization.json import ComplexSerializableType +from sec_certs.utils import helpers from sec_certs.utils.parallel_processing import process_parallel from sec_certs.utils.tqdm import tqdm @@ -34,7 +33,7 @@ class CVEDataset(JSONPathDataset, ComplexSerializableType): def __init__(self, cves: dict[str, CVE], json_path: str | Path = constants.DUMMY_NONEXISTING_PATH): self.cves = cves self.json_path = Path(json_path) - self.cpe_to_cve_ids_lookup: dict[str, set[str]] = dict() + self.cpe_to_cve_ids_lookup: dict[str, set[str]] = {} self.cves_with_vulnerable_configurations: list[CVE] = [] @property @@ -72,7 +71,7 @@ class CVEDataset(JSONPathDataset, ComplexSerializableType): - CPE(uri='cpe:2.3:a:bayashi:dopvcomet\\*:0009:b:*:*:*:*:*:*', title=None, version='0009', vendor='bayashi', item_name='dopvcomet\\*', start_version=None, end_version=None) - CPE(uri='cpe:2.3:a:bayashi:dopvstar\\*:0091:*:*:*:*:*:*:*', title=None, version='0091', vendor='bayashi', item_name='dopvstar\\*', start_version=None, end_version=None) """ - self.cpe_to_cve_ids_lookup = dict() + self.cpe_to_cve_ids_lookup = {} self.cves = {x.cve_id.upper(): x for x in self} logger.info("Getting CPE matching dictionary from NIST.gov") @@ -134,12 +133,11 @@ class CVEDataset(JSONPathDataset, ComplexSerializableType): cls.download_cves(tmp_dir, start_year, end_year) json_files = glob.glob(tmp_dir + "/*.json") - all_cves = dict() + all_cves = {} logger.info("Downloaded required resources. Building CVEDataset from jsons.") results = process_parallel( cls.from_nist_json, json_files, - config.n_threads, use_threading=False, progress_bar_desc="Building CVEDataset from jsons", ) @@ -247,7 +245,7 @@ class CVEDataset(JSONPathDataset, ComplexSerializableType): with input_filepath.open("r") as handle: match_data = json.load(handle) - mapping_dict = dict() + mapping_dict = {} for match in tqdm(match_data["matches"], desc="parsing cpe matching (by NIST) dictionary"): key = parse_key_cpe(match) value = parse_values_cpe(match) diff --git a/src/sec_certs/dataset/dataset.py b/src/sec_certs/dataset/dataset.py index a7120cef..9481d9f7 100644 --- a/src/sec_certs/dataset/dataset.py +++ b/src/sec_certs/dataset/dataset.py @@ -14,8 +14,7 @@ from typing import Any, Generic, Iterator, TypeVar, cast import pandas as pd -import sec_certs.constants as constants -import sec_certs.utils.helpers as helpers +from sec_certs import constants from sec_certs.config.configuration import config from sec_certs.dataset.cpe import CPEDataset from sec_certs.dataset.cve import CVEDataset @@ -23,23 +22,24 @@ from sec_certs.model.cpe_matching import CPEClassifier from sec_certs.sample.certificate import Certificate from sec_certs.sample.cpe import CPE from sec_certs.serialization.json import ComplexSerializableType, get_class_fullname, serialize +from sec_certs.utils import helpers from sec_certs.utils.tqdm import tqdm logger = logging.getLogger(__name__) @dataclass -class AuxillaryDatasets: +class AuxiliaryDatasets: cpe_dset: CPEDataset | None = None cve_dset: CVEDataset | None = None CertSubType = TypeVar("CertSubType", bound=Certificate) -AuxillaryDatasetsSubType = TypeVar("AuxillaryDatasetsSubType", bound=AuxillaryDatasets) +AuxiliaryDatasetsSubType = TypeVar("AuxiliaryDatasetsSubType", bound=AuxiliaryDatasets) DatasetSubType = TypeVar("DatasetSubType", bound="Dataset") -class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializableType, ABC): +class Dataset(Generic[CertSubType, AuxiliaryDatasetsSubType], ComplexSerializableType, ABC): """ Base class for dataset of certificates from CC and FIPS 140 schemes. Layouts public functions, the processing pipeline and common operations on the dataset and certs. @@ -50,20 +50,17 @@ class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializabl meta_sources_parsed: bool = False artifacts_downloaded: bool = False pdfs_converted: bool = False - auxillary_datasets_processed: bool = False + auxiliary_datasets_processed: bool = False certs_analyzed: bool = False - def __bool__(self): - return any(vars(self)) - def __init__( self, - certs: dict[str, CertSubType] = dict(), + certs: dict[str, CertSubType] = {}, root_dir: str | Path = constants.DUMMY_NONEXISTING_PATH, name: str | None = None, description: str = "", state: DatasetInternalState | None = None, - auxillary_datasets: AuxillaryDatasetsSubType | None = None, + auxiliary_datasets: AuxiliaryDatasetsSubType | None = None, ): self.certs = certs @@ -73,10 +70,10 @@ class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializabl self.description = description if description else "No description provided" self.state = state if state else self.DatasetInternalState() - if not auxillary_datasets: - self.auxillary_datasets = AuxillaryDatasets() + if not auxiliary_datasets: + self.auxiliary_datasets = AuxiliaryDatasets() else: - self.auxillary_datasets = auxillary_datasets + self.auxiliary_datasets = auxiliary_datasets self.root_dir = Path(root_dir) @@ -108,11 +105,11 @@ class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializabl return self.root_dir / "web" @property - def auxillary_datasets_dir(self) -> Path: + def auxiliary_datasets_dir(self) -> Path: """ - Path to directory with auxillary datasets. + Path to directory with auxiliary datasets. """ - return self.root_dir / "auxillary_datasets" + return self.root_dir / "auxiliary_datasets" @property def certs_dir(self) -> Path: @@ -123,15 +120,15 @@ class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializabl @property def cpe_dataset_path(self) -> Path: - return self.auxillary_datasets_dir / "cpe_dataset.json" + return self.auxiliary_datasets_dir / "cpe_dataset.json" @property def cve_dataset_path(self) -> Path: - return self.auxillary_datasets_dir / "cve_dataset.json" + return self.auxiliary_datasets_dir / "cve_dataset.json" @property def nist_cve_cpe_matching_dset_path(self) -> Path: - return self.auxillary_datasets_dir / "nvdcpematch-1.0.json" + return self.auxiliary_datasets_dir / "nvdcpematch-1.0.json" @property def json_path(self) -> Path: @@ -205,10 +202,10 @@ class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializabl return dset def _set_local_paths(self) -> None: - if self.auxillary_datasets.cpe_dset: - self.auxillary_datasets.cpe_dset.json_path = self.cpe_dataset_path - if self.auxillary_datasets.cve_dset: - self.auxillary_datasets.cve_dset.json_path = self.cve_dataset_path + if self.auxiliary_datasets.cpe_dset: + self.auxiliary_datasets.cpe_dset.json_path = self.cpe_dataset_path + if self.auxiliary_datasets.cve_dset: + self.auxiliary_datasets.cve_dset.json_path = self.cve_dataset_path def move_dataset(self, new_root_dir: str | Path) -> None: """ @@ -249,15 +246,15 @@ class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializabl @serialize @abstractmethod - def process_auxillary_datasets(self, download_fresh: bool = False) -> None: + def process_auxiliary_datasets(self, download_fresh: bool = False) -> None: """ - Processes all auxillary datasets (CPE, CVE, ...) that are required during computation. + Processes all auxiliary datasets (CPE, CVE, ...) that are required during computation. """ - logger.info("Processing auxillary datasets.") - self.auxillary_datasets_dir.mkdir(parents=True, exist_ok=True) - self.auxillary_datasets.cpe_dset = self._prepare_cpe_dataset(download_fresh) - self.auxillary_datasets.cve_dset = self._prepare_cve_dataset(download_fresh_cves=download_fresh) - self.state.auxillary_datasets_processed = True + logger.info("Processing auxiliary datasets.") + self.auxiliary_datasets_dir.mkdir(parents=True, exist_ok=True) + self.auxiliary_datasets.cpe_dset = self._prepare_cpe_dataset(download_fresh) + self.auxiliary_datasets.cve_dset = self._prepare_cve_dataset(download_fresh_cves=download_fresh) + self.state.auxiliary_datasets_processed = True @serialize def download_all_artifacts(self, fresh: bool = True) -> None: @@ -311,9 +308,9 @@ class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializabl "Attempting run analysis of txt files while not having the pdf->txt conversion done. Returning." ) return - if not self.state.auxillary_datasets_processed: + if not self.state.auxiliary_datasets_processed: logger.info( - "Attempting to run analysis of certifies while not having the auxillary datasets processed. Returning." + "Attempting to run analysis of certifies while not having the auxiliary datasets processed. Returning." ) logger.info("Analyzing certificates.") @@ -345,8 +342,8 @@ class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializabl def _prepare_cpe_dataset(self, download_fresh_cpes: bool = False) -> CPEDataset: logger.info("Preparing CPE dataset.") - if not self.auxillary_datasets_dir.exists(): - self.auxillary_datasets_dir.mkdir(parents=True) + if not self.auxiliary_datasets_dir.exists(): + self.auxiliary_datasets_dir.mkdir(parents=True) if not self.cpe_dataset_path.exists() or download_fresh_cpes is True: cpe_dataset = CPEDataset.from_web(self.cpe_dataset_path) @@ -360,8 +357,8 @@ class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializabl self, download_fresh_cves: bool = False, use_nist_cpe_matching_dict: bool = True ) -> CVEDataset: logger.info("Preparing CVE dataset.") - if not self.auxillary_datasets_dir.exists(): - self.auxillary_datasets_dir.mkdir(parents=True) + if not self.auxiliary_datasets_dir.exists(): + self.auxiliary_datasets_dir.mkdir(parents=True) if not self.cve_dataset_path.exists() or download_fresh_cves is True: cve_dataset = CVEDataset.from_web(json_path=self.cve_dataset_path) @@ -392,32 +389,32 @@ class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializabl and not any(char.isdigit() for char in cpe.title) ): return False - elif ( + if ( not cpe.title and cpe.item_name and (cpe.version == "-" or cpe.version == "*") and not any(char.isdigit() for char in cpe.item_name) ): return False - elif re.match(constants.RELEASE_CANDIDATE_REGEX, cpe.update): + if re.match(constants.RELEASE_CANDIDATE_REGEX, cpe.update): return False - elif cpe in WINDOWS_WEAK_CPES: + if cpe in WINDOWS_WEAK_CPES: return False return True logger.info("Computing heuristics: Finding CPE matches for certificates") - if not self.auxillary_datasets.cpe_dset or download_fresh_cpes: - self.auxillary_datasets.cpe_dset = self._prepare_cpe_dataset(download_fresh_cpes) + if not self.auxiliary_datasets.cpe_dset or download_fresh_cpes: + self.auxiliary_datasets.cpe_dset = self._prepare_cpe_dataset(download_fresh_cpes) # Temporarily disabled, see: https://github.com/crocs-muni/sec-certs/issues/173 # if not cpe_dset.was_enhanced_with_vuln_cpes: - # self.auxillary_datasets.cve_dset = self._prepare_cve_dataset(download_fresh_cves=False) - # self.auxillary_datasets.cpe_dset.enhance_with_cpes_from_cve_dataset(cve_dset) # this also calls build_lookup_dicts() on cpe_dset + # self.auxiliary_datasets.cve_dset = self._prepare_cve_dataset(download_fresh_cves=False) + # self.auxiliary_datasets.cpe_dset.enhance_with_cpes_from_cve_dataset(cve_dset) # this also calls build_lookup_dicts() on cpe_dset # else: - # self.auxillary_datasets.cpe_dset.build_lookup_dicts() + # self.auxiliary_datasets.cpe_dset.build_lookup_dicts() clf = CPEClassifier(config.cpe_matching_threshold, config.cpe_n_max_matches) - clf.fit([x for x in self.auxillary_datasets.cpe_dset if filter_condition(x)]) + clf.fit([x for x in self.auxiliary_datasets.cpe_dset if filter_condition(x)]) cert: CertSubType for cert in tqdm(self, desc="Predicting CPE matches with the classifier"): @@ -456,9 +453,7 @@ class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializabl logger.info("Translating label studio matches into their CPE representations and assigning to certificates.") for annotation in tqdm(data, desc="Translating label studio matches"): - cpe_candidate_keys = { - key for key in annotation.keys() if "option_" in key and annotation[key] != "No good match" - } + cpe_candidate_keys = {key for key in annotation if "option_" in key and annotation[key] != "No good match"} if "verified_cpe_match" not in annotation: incorrect_keys: set[str] = set() @@ -517,8 +512,8 @@ class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializabl Computes CVEs for the certificates, given their CPE matches. """ logger.info("Retrieving related CVEs to verified CPE matches") - if download_fresh_cves or not self.auxillary_datasets.cve_dset: - self.auxillary_datasets.cve_dset = self._prepare_cve_dataset( + if download_fresh_cves or not self.auxiliary_datasets.cve_dset: + self.auxiliary_datasets.cve_dset = self._prepare_cve_dataset( download_fresh_cves, use_nist_cpe_matching_dict ) @@ -533,12 +528,12 @@ class Dataset(Generic[CertSubType, AuxillaryDatasetsSubType], ComplexSerializabl return relevant_cpes = set(itertools.chain.from_iterable(x.heuristics.cpe_matches for x in cpe_rich_certs)) - self.auxillary_datasets.cve_dset.filter_related_cpes(relevant_cpes) + self.auxiliary_datasets.cve_dset.filter_related_cpes(relevant_cpes) cert: Certificate for cert in tqdm(cpe_rich_certs, desc="Computing related CVES"): if cert.heuristics.cpe_matches: - related_cves = self.auxillary_datasets.cve_dset.get_cves_from_matched_cpes(cert.heuristics.cpe_matches) + related_cves = self.auxiliary_datasets.cve_dset.get_cves_from_matched_cpes(cert.heuristics.cpe_matches) if related_cves: cert.heuristics.related_cves = related_cves diff --git a/src/sec_certs/dataset/fips.py b/src/sec_certs/dataset/fips.py index 14571f93..ce7563a0 100644 --- a/src/sec_certs/dataset/fips.py +++ b/src/sec_certs/dataset/fips.py @@ -15,7 +15,7 @@ from sec_certs import constants from sec_certs.config.configuration import config from sec_certs.dataset.cpe import CPEDataset from sec_certs.dataset.cve import CVEDataset -from sec_certs.dataset.dataset import AuxillaryDatasets, Dataset +from sec_certs.dataset.dataset import AuxiliaryDatasets, Dataset from sec_certs.dataset.fips_algorithm import FIPSAlgorithmDataset from sec_certs.model.reference_finder import ReferenceFinder from sec_certs.model.transitive_vulnerability_finder import TransitiveVulnerabilityFinder @@ -28,25 +28,25 @@ from sec_certs.utils.helpers import fips_dgst logger = logging.getLogger(__name__) -class FIPSAuxillaryDatasets(AuxillaryDatasets): +class FIPSAuxiliaryDatasets(AuxiliaryDatasets): cpe_dset: CPEDataset | None = None cve_dset: CVEDataset | None = None algorithm_dset: FIPSAlgorithmDataset | None = None -class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerializableType): +class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxiliaryDatasets], ComplexSerializableType): """ Class for processing of FIPSCertificate samples. Inherits from `ComplexSerializableType` and base abstract `Dataset` class. """ def __init__( self, - certs: dict[str, FIPSCertificate] = dict(), + certs: dict[str, FIPSCertificate] = {}, root_dir: str | Path = constants.DUMMY_NONEXISTING_PATH, name: str | None = None, description: str = "", state: Dataset.DatasetInternalState | None = None, - auxillary_datasets: FIPSAuxillaryDatasets | None = None, + auxiliary_datasets: FIPSAuxiliaryDatasets | None = None, ): self.certs = certs self.timestamp = datetime.datetime.now() @@ -54,8 +54,8 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial self.name = name if name else type(self).__name__ + " dataset" self.description = description if description else datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S") self.state = state if state else self.DatasetInternalState() - self.auxillary_datasets: FIPSAuxillaryDatasets = ( - auxillary_datasets if auxillary_datasets else FIPSAuxillaryDatasets() + self.auxiliary_datasets: FIPSAuxiliaryDatasets = ( + auxiliary_datasets if auxiliary_datasets else FIPSAuxiliaryDatasets() ) self.root_dir = Path(root_dir) @@ -84,7 +84,7 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial @property def algorithm_dataset_path(self) -> Path: - return self.auxillary_datasets_dir / "algorithms.json" + return self.auxiliary_datasets_dir / "algorithms.json" def __getitem__(self, item: str) -> FIPSCertificate: try: @@ -102,7 +102,6 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial processed_certs = cert_processing.process_parallel( FIPSCertificate.parse_html_module, certs_to_process, - config.n_threads, use_threading=False, progress_bar_desc="Extracting data from html modules", ) @@ -126,7 +125,6 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial processed_certs = cert_processing.process_parallel( FIPSCertificate.extract_policy_pdf_keywords, certs_to_process, - config.n_threads, use_threading=False, progress_bar_desc="Extracting keywords from policy pdfs", ) @@ -148,7 +146,6 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial cert_processing.process_parallel( FIPSCertificate.download_module, certs_to_process, - config.n_threads, progress_bar_desc="Downloading HTML modules", ) @@ -164,7 +161,6 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial cert_processing.process_parallel( FIPSCertificate.download_policy, certs_to_process, - config.n_threads, progress_bar_desc="Downloading PDF security policies", ) @@ -185,25 +181,24 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial cert_processing.process_parallel( FIPSCertificate.convert_policy_pdf, certs_to_process, - config.n_threads, progress_bar_desc="Converting policies to pdf", ) def _download_html_resources(self) -> None: logger.info("Downloading HTML files that list FIPS certificates.") html_urls = list(FIPSDataset.LIST_OF_CERTS_HTML.values()) - html_paths = [self.web_dir / x for x in FIPSDataset.LIST_OF_CERTS_HTML.keys()] + html_paths = [self.web_dir / x for x in FIPSDataset.LIST_OF_CERTS_HTML] helpers.download_parallel(html_urls, html_paths) def _get_all_certs_from_html_sources(self) -> list[FIPSCertificate]: return list( itertools.chain.from_iterable( - self._get_certificates_from_html(self.web_dir / x) for x in self.LIST_OF_CERTS_HTML.keys() + self._get_certificates_from_html(self.web_dir / x) for x in self.LIST_OF_CERTS_HTML ) ) def _get_certificates_from_html(self, html_file: Path) -> list[FIPSCertificate]: - with open(html_file, encoding="utf-8") as handle: + with html_file.open("r", encoding="utf-8") as handle: html = BeautifulSoup(handle.read(), "html5lib") table = [x for x in html.find(id="searchResultsTable").tbody.contents if x != "\n"] @@ -216,7 +211,7 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial if cert_id not in cert_ids: cert_ids.add(cert_id) - return [FIPSCertificate(cert_id) for cert_id in cert_ids] + return [FIPSCertificate(int(cert_id)) for cert_id in cert_ids] @classmethod def from_web_latest(cls) -> FIPSDataset: @@ -227,8 +222,8 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial def _set_local_paths(self) -> None: super()._set_local_paths() - if self.auxillary_datasets.algorithm_dset: - self.auxillary_datasets.algorithm_dset.json_path = self.algorithm_dataset_path + if self.auxiliary_datasets.algorithm_dset: + self.auxiliary_datasets.algorithm_dset.json_path = self.algorithm_dataset_path cert: FIPSCertificate for cert in self.certs.values(): @@ -252,9 +247,9 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial self.state.meta_sources_parsed = True @serialize - def process_auxillary_datasets(self, download_fresh: bool = False) -> None: - super().process_auxillary_datasets(download_fresh) - self.auxillary_datasets.algorithm_dset = self._prepare_algorithm_dataset(download_fresh) + def process_auxiliary_datasets(self, download_fresh: bool = False) -> None: + super().process_auxiliary_datasets(download_fresh) + self.auxiliary_datasets.algorithm_dset = self._prepare_algorithm_dataset(download_fresh) def _prepare_algorithm_dataset(self, download_fresh_algs: bool = False) -> FIPSAlgorithmDataset: logger.info("Preparing FIPSAlgorithm dataset.") @@ -272,7 +267,6 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial cert_processing.process_parallel( FIPSCertificate.get_algorithms_from_policy_tables, certs_to_process, - config.n_threads, use_threading=False, progress_bar_desc="Extracting Algorithms from policy tables", ) @@ -283,7 +277,6 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial processed_certs = cert_processing.process_parallel( FIPSCertificate.extract_policy_pdf_metadata, certs_to_process, - config.n_threads, use_threading=False, progress_bar_desc="Extracting security policy metadata", ) @@ -291,7 +284,7 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial def _compute_transitive_vulnerabilities(self) -> None: logger.info("Computing heuristics: Computing transitive vulnerabilities in referenc(ed/ing) certificates.") - transitive_cve_finder = TransitiveVulnerabilityFinder(lambda cert: cert.cert_id) + transitive_cve_finder = TransitiveVulnerabilityFinder(lambda cert: str(cert.cert_id)) transitive_cve_finder.fit(self.certs, lambda cert: cert.heuristics.policy_processed_references) for dgst in self.certs: @@ -304,7 +297,7 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial cert.prune_referenced_cert_ids() # Previously, a following procedure was used to prune reference_candidates: - # - A set of algorithms was obtained via self.auxillary_datasets.algorithm_dset.get_algorithms_by_id(reference_candidate) + # - A set of algorithms was obtained via self.auxiliary_datasets.algorithm_dset.get_algorithms_by_id(reference_candidate) # - If any of these algorithms had the same vendor as the reference_candidate, the candidate was rejected # - The rationale is that if an ID appears in a certificate s.t. an algorithm with the same ID was produced by the same vendor, the reference likely refers to alg. # - Such reference should then be discarded. @@ -316,12 +309,12 @@ class FIPSDataset(Dataset[FIPSCertificate, FIPSAuxillaryDatasets], ComplexSerial policy_reference_finder = ReferenceFinder() policy_reference_finder.fit( - self.certs, lambda cert: cert.cert_id, lambda cert: cert.heuristics.policy_prunned_references + self.certs, lambda cert: str(cert.cert_id), lambda cert: cert.heuristics.policy_prunned_references ) module_reference_finder = ReferenceFinder() module_reference_finder.fit( - self.certs, lambda cert: cert.cert_id, lambda cert: cert.heuristics.module_prunned_references + self.certs, lambda cert: str(cert.cert_id), lambda cert: cert.heuristics.module_prunned_references ) for cert in self: diff --git a/src/sec_certs/dataset/fips_algorithm.py b/src/sec_certs/dataset/fips_algorithm.py index c48cff07..df113381 100644 --- a/src/sec_certs/dataset/fips_algorithm.py +++ b/src/sec_certs/dataset/fips_algorithm.py @@ -20,12 +20,10 @@ logger = logging.getLogger(__name__) class FIPSAlgorithmDataset(JSONPathDataset, ComplexSerializableType): - def __init__( - self, algs: dict[str, FIPSAlgorithm] = dict(), json_path: str | Path = constants.DUMMY_NONEXISTING_PATH - ): + def __init__(self, algs: dict[str, FIPSAlgorithm] = {}, json_path: str | Path = constants.DUMMY_NONEXISTING_PATH): self.algs = algs self.json_path = Path(json_path) - self.alg_number_to_algs: dict[str, set[FIPSAlgorithm]] = dict() + self.alg_number_to_algs: dict[str, set[FIPSAlgorithm]] = {} self._build_lookup_dicts() @@ -48,7 +46,7 @@ class FIPSAlgorithmDataset(JSONPathDataset, ComplexSerializableType): def __contains__(self, item: FIPSAlgorithm) -> bool: if not isinstance(item, FIPSAlgorithm): raise ValueError(f"{item} is not of FIPSAlgorithm class") - return item.dgst in self.algs.keys() and self.algs[item.dgst] == item + return item.dgst in self.algs and self.algs[item.dgst] == item def __eq__(self, other: object) -> bool: return isinstance(other, FIPSAlgorithmDataset) and self.algs == other.algs @@ -109,9 +107,7 @@ class FIPSAlgorithmDataset(JSONPathDataset, ComplexSerializableType): return set(df["alg"]) def to_pandas(self) -> pd.DataFrame: - df = pd.DataFrame([x.pandas_tuple for x in self], columns=FIPSAlgorithm.pandas_columns) - df = df.set_index("dgst") - return df + return pd.DataFrame([x.pandas_tuple for x in self], columns=FIPSAlgorithm.pandas_columns).set_index("dgst") def _build_lookup_dicts(self) -> None: for alg in self: diff --git a/src/sec_certs/dataset/protection_profile.py b/src/sec_certs/dataset/protection_profile.py index e4f9f4b8..9730a477 100644 --- a/src/sec_certs/dataset/protection_profile.py +++ b/src/sec_certs/dataset/protection_profile.py @@ -7,11 +7,11 @@ import tempfile from dataclasses import dataclass from pathlib import Path -import sec_certs.utils.helpers as helpers from sec_certs import constants from sec_certs.config.configuration import config from sec_certs.sample.protection_profile import ProtectionProfile from sec_certs.serialization.json import get_class_fullname +from sec_certs.utils import helpers logger = logging.getLogger(__name__) diff --git a/src/sec_certs/model/cpe_matching.py b/src/sec_certs/model/cpe_matching.py index 0febea5d..5d08d7af 100644 --- a/src/sec_certs/model/cpe_matching.py +++ b/src/sec_certs/model/cpe_matching.py @@ -8,7 +8,6 @@ from typing import Pattern import spacy from rapidfuzz import fuzz -from sklearn.base import BaseEstimator from sec_certs import cert_rules, constants from sec_certs.sample.cpe import CPE @@ -17,10 +16,10 @@ from sec_certs.utils.tqdm import tqdm logger = logging.getLogger(__name__) -class CPEClassifier(BaseEstimator): +class CPEClassifier: """ Class that can predict CPE matches for certificate instances. - Adheres to sklearn BaseEstimator interface. + Adheres to sklearn `sklearn.base.BaseEstimator` interface. Fit method is called on list of CPEs and build two look-up dictionaries, see description of attributes. """ @@ -66,7 +65,7 @@ class CPEClassifier(BaseEstimator): sufficiently_long_cpes = self._filter_short_cpes(X) self.vendor_to_versions_ = {x.vendor: set() for x in sufficiently_long_cpes} self.vendors_ = set(self.vendor_to_versions_.keys()) - self.vendor_version_to_cpe_ = dict() + self.vendor_version_to_cpe_ = {} for cpe in tqdm(sufficiently_long_cpes, desc="Fitting the CPE classifier"): self.vendor_to_versions_[cpe.vendor].add(cpe.version) @@ -148,7 +147,7 @@ class CPEClassifier(BaseEstimator): def filter_condition(regex: Pattern, cpe: CPE, min_value: int, soft: bool = True): if matches := re.findall(regex, cpe.update): return int(re.findall(r"\d+", matches[0])[0]) >= min_value - return True if soft else False + return soft update_regexes = [cert_rules.SERVICE_PACK_RE, cert_rules.RELEASE_RE] @@ -161,7 +160,7 @@ class CPEClassifier(BaseEstimator): return cpes def _filter_candidates_by_platform(self, cpes: list[CPE], cert_title: str) -> list[CPE]: - def filter_condition(cpe: CPE, cert_platforms: set[str]): + def filter_condition(cpe: CPE, cert_platforms: set[str]) -> bool: if not cert_platforms and cpe.target_hw == "*": return True if cert_platforms and cpe.target_hw == "*": @@ -180,8 +179,9 @@ class CPEClassifier(BaseEstimator): ) if not target_hw_platforms: return can_return_true - else: - return can_return_true and target_hw_platforms[0] in cert_platforms + + return can_return_true and target_hw_platforms[0] in cert_platforms + return True crt_platforms = { platform for platform, regex in cert_rules.PLATFORM_REGEXES.items() if re.search(regex, cert_title) @@ -323,7 +323,7 @@ class CPEClassifier(BaseEstimator): itertools.chain.from_iterable([x.strip() for x in manufacturer.split(s)] for s in splits) ) result_aux = [self._get_candidate_list_of_vendors(x) for x in vendor_tokens] - result_used = set(set(itertools.chain.from_iterable(x for x in result_aux if x))) + result_used = set(itertools.chain.from_iterable(x for x in result_aux if x)) return result_used if result_used else set() if manufacturer in self.vendors_: @@ -347,10 +347,7 @@ class CPEClassifier(BaseEstimator): def simple_startswith(seeked_version: str, checked_string: str) -> bool: if seeked_version == checked_string: return True - else: - return ( - checked_string.startswith(seeked_version) and not checked_string[len(seeked_version)].isdigit() - ) + return checked_string.startswith(seeked_version) and not checked_string[len(seeked_version)].isdigit() if not cpe_version: return False diff --git a/src/sec_certs/model/evaluation.py b/src/sec_certs/model/evaluation.py index 4d0243f6..6f14fda5 100644 --- a/src/sec_certs/model/evaluation.py +++ b/src/sec_certs/model/evaluation.py @@ -6,11 +6,11 @@ from pathlib import Path import numpy as np -import sec_certs.utils.helpers as helpers from sec_certs.dataset.cpe import CPEDataset from sec_certs.sample.cc import CCCertificate from sec_certs.sample.fips import FIPSCertificate from sec_certs.serialization.json import CustomJSONEncoder +from sec_certs.utils import helpers logger = logging.getLogger(__name__) diff --git a/src/sec_certs/model/reference_finder.py b/src/sec_certs/model/reference_finder.py index 117a8b9d..94a3b29f 100644 --- a/src/sec_certs/model/reference_finder.py +++ b/src/sec_certs/model/reference_finder.py @@ -23,7 +23,7 @@ class ReferenceFinder: The fit is called on a dictionary of certificates, builds a hashmap of references, and assigns references for each certificate in the dictionary. """ - def __init__(self): + def __init__(self: ReferenceFinder) -> None: self.references: ReferencesType = {} self.id_mapping: IDMapping = {} self._fitted: bool = False diff --git a/src/sec_certs/model/sar_transformer.py b/src/sec_certs/model/sar_transformer.py index 45c4f7d5..a60f7495 100644 --- a/src/sec_certs/model/sar_transformer.py +++ b/src/sec_certs/model/sar_transformer.py @@ -3,8 +3,6 @@ from __future__ import annotations import logging from typing import Dict, Iterable, cast -from sklearn.base import BaseEstimator, TransformerMixin - from sec_certs.sample.cc import CCCertificate from sec_certs.sample.sar import SAR, SAR_DICT_KEY @@ -12,10 +10,10 @@ logger = logging.getLogger(__name__) # TODO: Right now we ignore number of ocurrences for final SAR selection. If we keep it this way, we can discard that variable -class SARTransformer(BaseEstimator, TransformerMixin): +class SARTransformer: """ Class for transforming SARs defined in st_keywords and report_keywords dictionaries into SAR objects. - This class implements sklearn transformer interface, so fit_transform() can be called on it. + This class implements `sklearn.base.Transformer` interface, so fit_transform() can be called on it. """ def fit(self, certificates: Iterable[CCCertificate]) -> SARTransformer: @@ -27,6 +25,9 @@ class SARTransformer(BaseEstimator, TransformerMixin): """ return self + def fit_transform(self, X, y=None, **fit_params): + return self.fit(X).transform(X) + def transform(self, certificates: Iterable[CCCertificate]) -> list[set[SAR] | None]: """ Just a wrapper around transform_single_cert() called on an iterable of CCCertificate. @@ -128,7 +129,7 @@ class SARTransformer(BaseEstimator, TransformerMixin): :param dgst: DIgest of the processed certificate. :return: _description_ """ - sars: dict[str, tuple[SAR, int]] = dict() + sars: dict[str, tuple[SAR, int]] = {} for sar_class, class_matches in dct.items(): for sar_string, n_occurences in class_matches.items(): try: diff --git a/src/sec_certs/model/transitive_vulnerability_finder.py b/src/sec_certs/model/transitive_vulnerability_finder.py index de733481..5eafea93 100644 --- a/src/sec_certs/model/transitive_vulnerability_finder.py +++ b/src/sec_certs/model/transitive_vulnerability_finder.py @@ -97,7 +97,7 @@ class TransitiveVulnerabilityFinder: thrown_away_cert_counter += 1 continue - self.vulnerabilities[cert.dgst] = dict() + self.vulnerabilities[cert.dgst] = {} self.vulnerabilities[cert.dgst][ReferenceType.DIRECT.value] = self._get_cert_transitive_cves( cert, ReferenceType.DIRECT, ref_func ) diff --git a/src/sec_certs/sample/cc.py b/src/sec_certs/sample/cc.py index 603c29f2..9f73aefa 100644 --- a/src/sec_certs/sample/cc.py +++ b/src/sec_certs/sample/cc.py @@ -17,13 +17,12 @@ from bs4 import Tag import sec_certs.utils.extract import sec_certs.utils.pdf import sec_certs.utils.sanitization -from sec_certs import constants as constants +from sec_certs import constants from sec_certs.cert_rules import SARS_IMPLIED_FROM_EAL, cc_rules, rules, security_level_csv_scan from sec_certs.sample.cc_certificate_id import canonicalize -from sec_certs.sample.certificate import Certificate +from sec_certs.sample.certificate import Certificate, References, logger from sec_certs.sample.certificate import Heuristics as BaseHeuristics from sec_certs.sample.certificate import PdfData as BasePdfData -from sec_certs.sample.certificate import References, logger from sec_certs.sample.protection_profile import ProtectionProfile from sec_certs.sample.sar import SAR from sec_certs.serialization.json import ComplexSerializableType @@ -117,10 +116,10 @@ class CCCertificate( st_txt_hash: str | None report_txt_hash: str | None - st_pdf_path: Path - report_pdf_path: Path - st_txt_path: Path - report_txt_path: Path + _st_pdf_path: Path | None = None + _report_pdf_path: Path | None = None + _st_txt_path: Path | None = None + _report_txt_path: Path | None = None def __init__( self, @@ -152,6 +151,46 @@ class CCCertificate( self.report_txt_hash = report_txt_hash @property + def st_pdf_path(self) -> Path: + if not self._st_pdf_path: + raise ValueError(f"st_pdf_path not set on {type(self)}") + return self._st_pdf_path + + @st_pdf_path.setter + def st_pdf_path(self, pth: str | Path | None) -> None: + self._st_pdf_path = Path(pth) if pth else None + + @property + def report_pdf_path(self) -> Path: + if not self._report_pdf_path: + raise ValueError(f"report_pdf_path not set on {type(self)}") + return self._report_pdf_path + + @report_pdf_path.setter + def report_pdf_path(self, pth: str | Path | None) -> None: + self._report_pdf_path = Path(pth) if pth else None + + @property + def st_txt_path(self) -> Path: + if not self._st_txt_path: + raise ValueError(f"st_txt_path not set on {type(self)}") + return self._st_txt_path + + @st_txt_path.setter + def st_txt_path(self, pth: str | Path | None) -> None: + self._st_txt_path = Path(pth) if pth else None + + @property + def report_txt_path(self) -> Path: + if not self._report_txt_path: + raise ValueError(f"report_txt_path not set on {type(self)}") + return self._report_txt_path + + @report_txt_path.setter + def report_txt_path(self, pth: str | Path | None) -> None: + self._report_txt_path = Path(pth) if pth else None + + @property def serialized_attributes(self) -> list[str]: return [ "st_download_ok", @@ -472,9 +511,9 @@ class CCCertificate( self.manufacturer_web = sec_certs.utils.sanitization.sanitize_link(manufacturer_web) self.protection_profiles = protection_profiles self.maintenance_updates = maintenance_updates - self.state = self.InternalState() if not state else state - self.pdf_data = self.PdfData() if not pdf_data else pdf_data - self.heuristics: CCCertificate.Heuristics = self.Heuristics() if not heuristics else heuristics + self.state = state if state else self.InternalState() + self.pdf_data = pdf_data if pdf_data else self.PdfData() + self.heuristics: CCCertificate.Heuristics = heuristics if heuristics else self.Heuristics() @property def dgst(self) -> str: @@ -507,7 +546,7 @@ class CCCertificate( Computes actual SARs. First, SARs implied by EAL are computed. Then, these are augmented with heuristically extracted SARs :return Optional[Set[SAR]]: Set of actual SARs of a certificate, None if empty """ - sars = dict() + sars = {} if self.eal: sars = {x[0]: SAR(x[0], x[1]) for x in SARS_IMPLIED_FROM_EAL[self.eal[:4]]} @@ -755,13 +794,13 @@ class CCCertificate( :param Optional[Union[str, Path]] report_txt_dir: Directory where txt reports shall be stored :param Optional[Union[str, Path]] st_txt_dir: Directory where txt security targets shall be stored """ - if report_pdf_dir is not None: + if report_pdf_dir: self.state.report_pdf_path = Path(report_pdf_dir) / (self.dgst + ".pdf") - if st_pdf_dir is not None: + if st_pdf_dir: self.state.st_pdf_path = Path(st_pdf_dir) / (self.dgst + ".pdf") - if report_txt_dir is not None: + if report_txt_dir: self.state.report_txt_path = Path(report_txt_dir) / (self.dgst + ".txt") - if st_txt_dir is not None: + if st_txt_dir: self.state.st_txt_path = Path(st_txt_dir) / (self.dgst + ".txt") @staticmethod @@ -795,11 +834,10 @@ class CCCertificate( :param CCCertificate cert: cert to download the pdf security target for :return CCCertificate: returns the modified certificate with updated state """ - exit_code: str | int - if not cert.st_link: - exit_code = "No link" - else: - exit_code = helpers.download_file(cert.st_link, cert.state.st_pdf_path) + exit_code: str | int = ( + helpers.download_file(cert.st_link, cert.state.st_pdf_path) if cert.st_link else "No link" + ) + if exit_code != requests.codes.ok: error_msg = f"failed to download ST from {cert.st_link}, code: {exit_code}" logger.error(f"Cert dgst: {cert.dgst} " + error_msg) diff --git a/src/sec_certs/sample/cc_maintenance_update.py b/src/sec_certs/sample/cc_maintenance_update.py index d78359fc..4273b25e 100644 --- a/src/sec_certs/sample/cc_maintenance_update.py +++ b/src/sec_certs/sample/cc_maintenance_update.py @@ -4,9 +4,9 @@ import logging from datetime import date from typing import ClassVar -import sec_certs.utils.helpers as helpers from sec_certs.sample.cc import CCCertificate from sec_certs.serialization.json import ComplexSerializableType +from sec_certs.utils import helpers logger = logging.getLogger(__name__) diff --git a/src/sec_certs/sample/certificate.py b/src/sec_certs/sample/certificate.py index bb49c0df..5dab9cef 100644 --- a/src/sec_certs/sample/certificate.py +++ b/src/sec_certs/sample/certificate.py @@ -25,6 +25,9 @@ class References(ComplexSerializableType): directly_referencing: set[str] | None = field(default=None) indirectly_referencing: set[str] | None = field(default=None) + def __bool__(self): + return any(getattr(self, x) for x in vars(self)) + class Heuristics: cpe_matches: set[str] | None diff --git a/src/sec_certs/sample/fips.py b/src/sec_certs/sample/fips.py index aec791d4..b3ff8ba6 100644 --- a/src/sec_certs/sample/fips.py +++ b/src/sec_certs/sample/fips.py @@ -14,21 +14,16 @@ import requests from bs4 import BeautifulSoup, Tag from tabula import read_pdf -import sec_certs.constants as constants -import sec_certs.utils.extract -import sec_certs.utils.helpers as helpers -import sec_certs.utils.pdf -import sec_certs.utils.pdf as pdf -import sec_certs.utils.tables as tables +from sec_certs import constants from sec_certs.cert_rules import FIPS_ALGS_IN_TABLE, fips_rules from sec_certs.config.configuration import config -from sec_certs.sample.certificate import Certificate +from sec_certs.sample.certificate import Certificate, References, logger from sec_certs.sample.certificate import Heuristics as BaseHeuristics from sec_certs.sample.certificate import PdfData as BasePdfData -from sec_certs.sample.certificate import References, logger from sec_certs.sample.cpe import CPE from sec_certs.serialization.json import ComplexSerializableType from sec_certs.serialization.pandas import PandasSerializableType +from sec_certs.utils import extract, helpers, pdf, tables from sec_certs.utils.helpers import fips_dgst @@ -69,7 +64,7 @@ class FIPSHTMLParser: [x.find("div", class_="col-md-3") for x in entries], [x.find("div", class_="col-md-9") for x in entries] ) entries = [(FIPSHTMLParser.normalize_string(key.text), entry) for key, entry in entries] - entries = [parse_single_detail_entry(*x) for x in entries if x[0] in DETAILS_KEY_NORMALIZATION_DICT.keys()] + entries = [parse_single_detail_entry(*x) for x in entries if x[0] in DETAILS_KEY_NORMALIZATION_DICT] entries = {x: y for x, y in entries} if "caveat" in entries: @@ -130,11 +125,22 @@ class FIPSHTMLParser: @staticmethod def parse_algorithms(algorithms_div: Tag) -> dict[str, set[str]]: - rows = algorithms_div.find("tbody").find_all("tr") - dct: dict[str, set[str]] = dict() - for row in rows: - cells = row.find_all("td") - dct[cells[0].text] = {m.group() for m in re.finditer(FIPS_ALGS_IN_TABLE, cells[1].text)} + dct: dict[str, set[str]] = {} + table = algorithms_div.find("tbody") + # Two types of organization on the CMVP website: + # - One is a table with algo references in text + # - Other is just divs for rows, one per algo + if table: + rows = table.find_all("tr") + for row in rows: + cells = row.find_all("td") + dct[str(cells[0].text)] = {m.group() for m in re.finditer(FIPS_ALGS_IN_TABLE, cells[1].text)} + else: + rows = algorithms_div.find_all("div", class_="col-md-12") + for row in rows: + dct[str(row.find("div", class_="col-md-3").text)] = { + str(row.find("div", class_="col-md-4").text).strip() + } return dct @staticmethod @@ -144,7 +150,7 @@ class FIPSHTMLParser: @staticmethod def parse_tested_configurations(tested_configurations: Tag) -> list[str] | None: configurations = [y.text for y in tested_configurations.find_all("li")] - return configurations if not configurations == ["N/A"] else None + return None if configurations == ["N/A"] else configurations @staticmethod def normalize_embodiment(embodiment_element: Tag) -> str: @@ -248,9 +254,9 @@ class FIPSCertificate( policy_pdf_hash: str | None policy_txt_hash: str | None - policy_pdf_path: Path - policy_txt_path: Path - module_html_path: Path + _policy_pdf_path: Path | None = None + _policy_txt_path: Path | None = None + _module_html_path: Path | None = None def __init__( self, @@ -273,6 +279,36 @@ class FIPSCertificate( self.policy_txt_hash = policy_txt_hash @property + def policy_pdf_path(self) -> Path: + if not self._policy_pdf_path: + raise ValueError(f"policy_pdf_path not set on {type(self)}") + return self._policy_pdf_path + + @policy_pdf_path.setter + def policy_pdf_path(self, pth: str | Path | None) -> None: + self._policy_pdf_path = Path(pth) if pth else None + + @property + def policy_txt_path(self) -> Path: + if not self._policy_txt_path: + raise ValueError(f"policy_txt_path not set on {type(self)}") + return self._policy_txt_path + + @policy_txt_path.setter + def policy_txt_path(self, pth: str | Path | None) -> None: + self._policy_txt_path = Path(pth) if pth else None + + @property + def module_html_path(self) -> Path: + if not self._module_html_path: + raise ValueError(f"module_html_path not set on {type(self)}") + return self._module_html_path + + @module_html_path.setter + def module_html_path(self, pth: str | Path | None) -> None: + self._module_html_path = Path(pth) if pth else None + + @property def serialized_attributes(self) -> list[str]: return [ "module_download_ok", @@ -389,8 +425,8 @@ class FIPSCertificate( def certlike_algorithm_numbers(self) -> set[str]: """Returns numbers of certificates from keywords["fips_certlike"]["Certlike"]""" if self.keywords and "fips_certlike" in self.keywords: - fips_certlike = self.keywords["fips_certlike"].get("Certlike", dict()) - matches = {re.search(r"#\s{0,1}\d{1,4}", x) for x in fips_certlike.keys()} + fips_certlike = self.keywords["fips_certlike"].get("Certlike", {}) + matches = {re.search(r"#\s{0,1}\d{1,4}", x) for x in fips_certlike} return {"".join([x for x in match.group() if x.isdigit()]) for match in matches if match} else: return set() @@ -463,7 +499,7 @@ class FIPSCertificate( def __init__( self, - cert_id: str, + cert_id: int, web_data: FIPSCertificate.WebData | None = None, pdf_data: FIPSCertificate.PdfData | None = None, heuristics: FIPSCertificate.Heuristics | None = None, @@ -543,9 +579,7 @@ class FIPSCertificate( """ Converts policy pdf -> txt """ - ocr_done, ok_result = sec_certs.utils.pdf.convert_pdf_file( - cert.state.policy_pdf_path, cert.state.policy_txt_path - ) + ocr_done, ok_result = pdf.convert_pdf_file(cert.state.policy_pdf_path, cert.state.policy_txt_path) # If OCR was done and the result was garbage cert.state.policy_convert_garbage = ocr_done @@ -565,12 +599,12 @@ class FIPSCertificate( """ Extract the PDF metadata from the security policy. """ - _, metadata = sec_certs.utils.pdf.extract_pdf_metadata(cert.state.policy_pdf_path) + _, metadata = pdf.extract_pdf_metadata(cert.state.policy_pdf_path) if metadata: cert.pdf_data.policy_metadata = metadata else: - cert.pdf_data.policy_metadata = dict() + cert.pdf_data.policy_metadata = {} cert.state.policy_extract_ok = False return cert @@ -579,7 +613,7 @@ class FIPSCertificate( """ Extract keywords from policy document """ - keywords = sec_certs.utils.extract.extract_keywords(cert.state.policy_txt_path, fips_rules) + keywords = extract.extract_keywords(cert.state.policy_txt_path, fips_rules) if not keywords: cert.state.policy_extract_ok = False else: @@ -618,7 +652,7 @@ class FIPSCertificate( self.heuristics.module_prunned_references = self._prune_reference_ids_variable(html_module_ids) if self.pdf_data.keywords: - pdf_policy_ids = set(self.pdf_data.keywords["fips_cert_id"].get("Cert", dict()).keys()) + pdf_policy_ids = set(self.pdf_data.keywords["fips_cert_id"].get("Cert", {}).keys()) pdf_policy_ids = {"".join([y for y in x if y.isdigit()]) for x in pdf_policy_ids} else: pdf_policy_ids = set() @@ -646,9 +680,7 @@ class FIPSCertificate( 2. Consider only ids s.t. they don't appear in self.heuristics.algorithms 3. Consider only ids s.t. they don't appear in self.pdf_data.keywords["fips_certlike"]["Certlike"] """ - prunned = {x for x in attribute_to_prune if x != self.cert_id} + prunned = {x for x in attribute_to_prune if x != str(self.cert_id)} prunned = {x for x in prunned if int(x) > config.always_false_positive_fips_cert_id_threshold} prunned = {x for x in prunned if x not in self.heuristics.algorithm_numbers} - prunned = {x for x in prunned if x not in self.pdf_data.certlike_algorithm_numbers} - - return prunned + return {x for x in prunned if x not in self.pdf_data.certlike_algorithm_numbers} diff --git a/src/sec_certs/sample/fips_iut.py b/src/sec_certs/sample/fips_iut.py index cb521ee4..f6010346 100644 --- a/src/sec_certs/sample/fips_iut.py +++ b/src/sec_certs/sample/fips_iut.py @@ -85,10 +85,11 @@ class IUTSnapshot(ComplexSerializableType): last_updated_elem = next( filter( - lambda e: isinstance(e, Tag) and e.name == "p", + lambda e: isinstance(e, Tag) and e.name == "p" and "Last Updated" in str(e.string), soup.find(id="content").next_siblings, ) ) + last_updated_text = str(last_updated_elem.string).strip() last_updated = datetime.strptime(last_updated_text, "Last Updated: %m/%d/%Y").date() table = tables[0].find("tbody") @@ -100,7 +101,7 @@ class IUTSnapshot(ComplexSerializableType): str(line[2].string), datetime.strptime(str(line[3].string), "%m/%d/%Y").date(), ) - for line in map(lambda tr: tr.find_all("td"), lines) + for line in (tr.find_all("td") for tr in lines) } # Parse footer diff --git a/src/sec_certs/sample/fips_mip.py b/src/sec_certs/sample/fips_mip.py index 6918d2aa..7e0ddff0 100644 --- a/src/sec_certs/sample/fips_mip.py +++ b/src/sec_certs/sample/fips_mip.py @@ -114,7 +114,7 @@ class MIPSnapshot(ComplexSerializableType): MIPEntry( str(line[0].string), str(line[1].string), str(line[2].string), MIPStatus(str(line[3].string)), None ) - for line in map(lambda tr: tr.find_all("td"), lines) + for line in (tr.find_all("td") for tr in lines) } @classmethod @@ -128,14 +128,14 @@ class MIPSnapshot(ComplexSerializableType): MIPStatus(str(line[3].string)), None, ) - for line in map(lambda tr: tr.find_all("td"), lines) + for line in (tr.find_all("td") for tr in lines) } @classmethod def _extract_entries_4(cls, lines): """Works now.""" entries = set() - for line in map(lambda tr: tr.find_all("td"), lines): + for line in (tr.find_all("td") for tr in lines): module_name = str(line[0].string) vendor_name = str(" ".join(line[1].find_all(text=True, recursive=False)).strip()) standard = str(line[2].string) @@ -150,14 +150,12 @@ class MIPSnapshot(ComplexSerializableType): @classmethod def _extract_entries(cls, lines, snapshot_date): if snapshot_date <= datetime(2020, 10, 28): - entries = cls._extract_entries_1(lines) - elif snapshot_date <= datetime(2021, 4, 20): - entries = cls._extract_entries_2(lines) - elif snapshot_date <= datetime(2022, 3, 23): - entries = cls._extract_entries_3(lines) - else: - entries = cls._extract_entries_4(lines) - return entries + return cls._extract_entries_1(lines) + if snapshot_date <= datetime(2021, 4, 20): + return cls._extract_entries_2(lines) + if snapshot_date <= datetime(2022, 3, 23): + return cls._extract_entries_3(lines) + return cls._extract_entries_4(lines) @classmethod def from_page(cls, content: bytes, snapshot_date: datetime) -> MIPSnapshot: diff --git a/src/sec_certs/sample/protection_profile.py b/src/sec_certs/sample/protection_profile.py index b7c2ec34..4c26a1c7 100644 --- a/src/sec_certs/sample/protection_profile.py +++ b/src/sec_certs/sample/protection_profile.py @@ -5,8 +5,8 @@ import logging from dataclasses import dataclass from typing import Any -import sec_certs.utils.sanitization as sanitization from sec_certs.serialization.json import ComplexSerializableType +from sec_certs.utils import sanitization logger = logging.getLogger(__name__) diff --git a/src/sec_certs/sample/sar.py b/src/sec_certs/sample/sar.py index 31359299..8f48f417 100644 --- a/src/sec_certs/sample/sar.py +++ b/src/sec_certs/sample/sar.py @@ -18,7 +18,7 @@ SAR_CLASS_MAPPING = { "ACO": "Comoposition", } -SAR_CLASSES = {x for x in SAR_CLASS_MAPPING} +SAR_CLASSES = set(SAR_CLASS_MAPPING) SAR_DICT_KEY = "cc_sar" diff --git a/src/sec_certs/serialization/json.py b/src/sec_certs/serialization/json.py index 69bbc2ff..7b523b9b 100644 --- a/src/sec_certs/serialization/json.py +++ b/src/sec_certs/serialization/json.py @@ -67,8 +67,7 @@ class ComplexSerializableType: def from_json(cls: type[T], input_path: str | Path) -> T: input_path = Path(input_path) with input_path.open("r") as handle: - obj = json.load(handle, cls=CustomJSONDecoder) - return obj + return json.load(handle, cls=CustomJSONDecoder) # Decorator for serialization @@ -95,10 +94,7 @@ def serialize(func: Callable): def get_class_fullname(obj: Any) -> str: - if isinstance(obj, type): - klass = obj - else: - klass = obj.__class__ + klass = obj if isinstance(obj, type) else obj.__class__ module = klass.__module__ if module == "builtins": return klass.__qualname__ @@ -112,9 +108,9 @@ class CustomJSONEncoder(json.JSONEncoder): if isinstance(obj, dict): return obj if isinstance(obj, set): - return {"_type": "Set", "elements": sorted(list(obj))} + return {"_type": "Set", "elements": sorted(obj)} if isinstance(obj, frozenset): - return sorted(list(obj)) + return sorted(obj) if isinstance(obj, date): return str(obj) if isinstance(obj, Path): @@ -136,10 +132,10 @@ class CustomJSONDecoder(json.JSONDecoder): def object_hook(self, obj): if "_type" in obj and obj["_type"] == "Set": return set(obj["elements"]) - if "_type" in obj and obj["_type"] in self.serializable_complex_types.keys(): + if "_type" in obj and obj["_type"] in self.serializable_complex_types: complex_type = obj.pop("_type") return self.serializable_complex_types[complex_type].from_dict(obj) - elif "_type" in obj: + if "_type" in obj: raise SerializationError(f"JSONDecoder doesn't know how to handle {obj}") return obj diff --git a/src/sec_certs/utils/extract.py b/src/sec_certs/utils/extract.py index 09460fb7..933db4b8 100644 --- a/src/sec_certs/utils/extract.py +++ b/src/sec_certs/utils/extract.py @@ -6,11 +6,11 @@ import re from collections import Counter from enum import Enum from pathlib import Path -from typing import Any, Iterator +from typing import Any import numpy as np -from sec_certs import constants as constants +from sec_certs import constants from sec_certs.cert_rules import REGEXEC_SEP, cc_rules from sec_certs.constants import FILE_ERRORS_STRATEGY, LINE_SEPARATOR, MAX_ALLOWED_MATCH_LENGTH @@ -585,11 +585,6 @@ def search_only_headers_canada(filepath: Path): # noqa: C901 return constants.RETURNCODE_OK, items_found -def search_files(folder: str | Path) -> Iterator[str]: - for root, _, files in os.walk(str(folder)): - yield from [os.path.join(root, x) for x in files] - - def flatten_matches(dct: dict) -> dict: """ Function to flatten dictionary of matches. @@ -663,13 +658,13 @@ def extract_keywords(filepath: Path, search_rules) -> dict[str, dict[str, int]] def extract(rules): if isinstance(rules, dict): return {k: extract(v) for k, v in rules.items()} - elif isinstance(rules, list): + if isinstance(rules, list): matches = [extract(rule) for rule in rules] c = Counter() for match_list in matches: c += Counter(match_list) return dict(c) - elif isinstance(rules, re.Pattern): + if isinstance(rules, re.Pattern): rule = rules matches = [] for match in rule.finditer(whole_text): @@ -719,7 +714,7 @@ def load_text_file( logger.warning("UnicodeDecodeError, opening as utf8") if was_unicode_decode_error: - with open(file_name, encoding="utf8", errors=FILE_ERRORS_STRATEGY) as f2: + with Path(file_name).open("r", encoding="utf8", errors=FILE_ERRORS_STRATEGY) as f2: # coding failure, try line by line line = " " while line: @@ -746,23 +741,31 @@ def load_text_file( return whole_text, whole_text_with_newlines, was_unicode_decode_error -def load_cert_html_file(file_name: str) -> str: - with open(file_name, errors=FILE_ERRORS_STRATEGY) as f: - try: - return f.read() - except UnicodeDecodeError: - logger.warning("UnicodeDecodeError, opening as utf8") +def rules_get_subset(desired_path: str) -> dict: + """ + + + + + + + + + + + + + + + + + + + + - with open(file_name, encoding="utf8", errors=FILE_ERRORS_STRATEGY) as f2: - try: - return f2.read() - except UnicodeDecodeError: - logger.error(f"Failed to read file {file_name}") - return "" -def rules_get_subset(desired_path: str) -> dict: - """ Recursively applies cc_certs.get(key) on tokens from desired_path, returns the keys of the inner-most layer. """ diff --git a/src/sec_certs/utils/helpers.py b/src/sec_certs/utils/helpers.py index 302f4e6a..596ecf62 100644 --- a/src/sec_certs/utils/helpers.py +++ b/src/sec_certs/utils/helpers.py @@ -14,8 +14,7 @@ import numpy as np import pkgconfig import requests -import sec_certs.constants as constants -from sec_certs.config.configuration import config +from sec_certs import constants from sec_certs.utils import parallel_processing from sec_certs.utils.tqdm import tqdm @@ -45,12 +44,11 @@ def download_file( ctx = nullcontext if r.status_code == requests.codes.ok: - with ctx() as pbar: - with output.open("wb") as f: - for data in r.iter_content(1024): - f.write(data) - if show_progress_bar: - pbar.update(len(data)) + with ctx() as pbar, output.open("wb") as f: + for data in r.iter_content(1024): + f.write(data) + if show_progress_bar: + pbar.update(len(data)) return r.status_code except requests.exceptions.Timeout: @@ -65,7 +63,7 @@ def download_parallel( urls: Collection[str], paths: Collection[Path], progress_bar_desc: str | None = None ) -> list[int]: exit_codes = parallel_processing.process_parallel( - download_file, list(zip(urls, paths)), config.n_threads, unpack=True, progress_bar_desc=progress_bar_desc + download_file, list(zip(urls, paths)), unpack=True, progress_bar_desc=progress_bar_desc ) n_successful = len([e for e in exit_codes if e == requests.codes.ok]) logger.info(f"Successfully downloaded {n_successful} files, {len(exit_codes) - n_successful} failed.") @@ -98,8 +96,7 @@ def to_utc(timestamp: datetime) -> datetime: if offset is None: return timestamp timestamp -= offset - timestamp = timestamp.replace(tzinfo=None) - return timestamp + return timestamp.replace(tzinfo=None) def is_in_dict(target_dict: dict, path: str) -> bool: @@ -107,8 +104,7 @@ def is_in_dict(target_dict: dict, path: str) -> bool: for item in path: if item not in current_level: return False - else: - current_level = current_level[item] + current_level = current_level[item] return True diff --git a/src/sec_certs/utils/pandas.py b/src/sec_certs/utils/pandas.py index b61d11d7..749292e3 100644 --- a/src/sec_certs/utils/pandas.py +++ b/src/sec_certs/utils/pandas.py @@ -140,7 +140,7 @@ def get_sar_level_from_set(sars: set[SAR], sar_family: str) -> int | None: """ Given a set of SARs and a family name, will return level of the seeked SAR from the set. """ - family_sars_dict = {x.family: x for x in sars} if (sars and not pd.isnull(sars)) else dict() + family_sars_dict = {x.family: x for x in sars} if (sars and not pd.isnull(sars)) else {} if sar_family not in family_sars_dict.keys(): return None return family_sars_dict[sar_family].level diff --git a/src/sec_certs/utils/parallel_processing.py b/src/sec_certs/utils/parallel_processing.py index 1101035f..b3016695 100644 --- a/src/sec_certs/utils/parallel_processing.py +++ b/src/sec_certs/utils/parallel_processing.py @@ -1,24 +1,29 @@ from __future__ import annotations import time +from multiprocessing import cpu_count from multiprocessing.pool import ThreadPool from typing import Any, Callable, Iterable from billiard.pool import Pool +from sec_certs.config.configuration import config from sec_certs.utils.tqdm import tqdm def process_parallel( func: Callable, items: Iterable, - max_workers: int, + max_workers: int = config.n_threads, callback: Callable | None = None, use_threading: bool = True, progress_bar: bool = True, unpack: bool = False, progress_bar_desc: str | None = None, ) -> list[Any]: + if max_workers == -1: + max_workers = cpu_count() + pool: Pool | ThreadPool = ThreadPool(max_workers) if use_threading else Pool(max_workers) results = ( [pool.apply_async(func, (*i,), callback=callback) for i in items] diff --git a/src/sec_certs/utils/pdf.py b/src/sec_certs/utils/pdf.py index d97dff95..edda0570 100644 --- a/src/sec_certs/utils/pdf.py +++ b/src/sec_certs/utils/pdf.py @@ -11,10 +11,10 @@ from typing import Any import pdftotext import pikepdf -from PyPDF2 import PdfFileReader -from PyPDF2.generic import BooleanObject, ByteStringObject, FloatObject, IndirectObject, NumberObject, TextStringObject +from pypdf import PdfReader +from pypdf.generic import BooleanObject, ByteStringObject, FloatObject, IndirectObject, NumberObject, TextStringObject -from sec_certs import constants as constants +from sec_certs import constants from sec_certs.constants import ( GARBAGE_ALPHA_CHARS_THRESHOLD, GARBAGE_AVG_LLEN_THRESHOLD, @@ -24,6 +24,7 @@ from sec_certs.constants import ( ) logger = logging.getLogger(__name__) +logging.getLogger("pypdf").setLevel(logging.ERROR) def repair_pdf(file: Path) -> None: @@ -165,7 +166,7 @@ def extract_pdf_metadata(filepath: Path) -> tuple[str, dict[str, Any] | None]: val = int(val) elif isinstance(val, IndirectObject) and not nope_out: # Let's make sure to nope out in case of cycles - val = map_metadata_value(val.getObject(), nope_out=True) + val = map_metadata_value(val.get_object(), nope_out=True) elif isinstance(val, TextStringObject): val = str(val) elif isinstance(val, ByteStringObject): @@ -180,27 +181,26 @@ def extract_pdf_metadata(filepath: Path) -> tuple[str, dict[str, Any] | None]: def resolve_indirect(val, bound=10): if isinstance(val, list) and bound: return [resolve_indirect(v, bound - 1) for v in val] - elif isinstance(val, IndirectObject) and bound: - return resolve_indirect(val.getObject(), bound - 1) - else: - return val + if isinstance(val, IndirectObject) and bound: + return resolve_indirect(val.get_object(), bound - 1) + return val - metadata: dict[str, Any] = dict() + metadata: dict[str, Any] = {} try: metadata["pdf_file_size_bytes"] = filepath.stat().st_size with filepath.open("rb") as handle: - pdf = PdfFileReader(handle, strict=False) - metadata["pdf_is_encrypted"] = pdf.getIsEncrypted() + pdf = PdfReader(handle, strict=False) + metadata["pdf_is_encrypted"] = pdf.is_encrypted # see https://stackoverflow.com/questions/26242952/pypdf-2-decrypt-not-working if metadata["pdf_is_encrypted"]: pikepdf.open(filepath, allow_overwriting_input=True).save() with filepath.open("rb") as handle: - pdf = PdfFileReader(handle, strict=False) - metadata["pdf_number_of_pages"] = pdf.getNumPages() - pdf_document_info = pdf.getDocumentInfo() + pdf = PdfReader(handle, strict=False) + metadata["pdf_number_of_pages"] = len(pdf.pages) + pdf_document_info = pdf.metadata if pdf_document_info is None: raise ValueError("PDF metadata unavailable") @@ -251,14 +251,8 @@ def text_is_garbage(text: str) -> bool: if len(set(line[1::2])) > 1: every_second += 1 - if lines: - avg_line_len = content_len / lines - else: - avg_line_len = 0 - if size: - alpha = alpha_len / size - else: - alpha = 0 + avg_line_len = content_len / lines if lines else 0 + alpha = alpha_len / size if size else 0 # If number of lines is small, this is garbage. if lines < GARBAGE_LINES_THRESHOLD: diff --git a/src/sec_certs/utils/sanitization.py b/src/sec_certs/utils/sanitization.py index 2f9cd046..3563e1f4 100644 --- a/src/sec_certs/utils/sanitization.py +++ b/src/sec_certs/utils/sanitization.py @@ -26,9 +26,9 @@ def sanitize_link(record: str | None) -> str | None: def sanitize_date(record: pd.Timestamp | date | np.datetime64) -> date | None: if pd.isnull(record): return None - elif isinstance(record, pd.Timestamp): + if isinstance(record, pd.Timestamp): return record.date() - elif isinstance(record, (date, type(None))): + if isinstance(record, (date, type(None))): return record raise ValueError("Unsupported type given as input") diff --git a/tests/cc/test_cc_analysis.py b/tests/cc/test_cc_analysis.py index a61c7e67..6d0f4cfe 100644 --- a/tests/cc/test_cc_analysis.py +++ b/tests/cc/test_cc_analysis.py @@ -4,8 +4,8 @@ import shutil from pathlib import Path import pytest - import tests.data.cc.analysis + from sec_certs.cert_rules import SARS_IMPLIED_FROM_EAL from sec_certs.dataset import CCDataset from sec_certs.dataset.cpe import CPEDataset @@ -91,7 +91,7 @@ def cc_dset(data_dir: Path, cve_dset: CVEDataset, tmp_path_factory) -> CCDataset cc_dset = CCDataset.from_json(tmp_dir / "vulnerable_dataset.json") cc_dset.process_protection_profiles() cc_dset.extract_data() - cc_dset.auxillary_datasets.cve_dset = cve_dset + cc_dset.auxiliary_datasets.cve_dset = cve_dset cc_dset._compute_heuristics() return cc_dset @@ -104,7 +104,7 @@ def cc_config_dset(data_dir: Path, cve_config_dset: CVEDataset, tmp_path_factory cc_config_dset = CCDataset.from_json(tmp_dir / "vulnerable_dataset.json") cc_config_dset.process_protection_profiles() cc_config_dset.extract_data() - cc_config_dset.auxillary_datasets.cve_dset = cve_config_dset + cc_config_dset.auxiliary_datasets.cve_dset = cve_config_dset cc_config_dset._compute_heuristics() return cc_config_dset diff --git a/tests/cc/test_cc_certificate.py b/tests/cc/test_cc_certificate.py index 2234ee11..2a5ff222 100644 --- a/tests/cc/test_cc_certificate.py +++ b/tests/cc/test_cc_certificate.py @@ -4,9 +4,9 @@ from datetime import date from pathlib import Path import pytest - import tests.data.cc.analysis import tests.data.cc.certificate + from sec_certs.dataset import CCDataset from sec_certs.sample import CCCertificate from sec_certs.sample.protection_profile import ProtectionProfile diff --git a/tests/cc/test_cc_dataset.py b/tests/cc/test_cc_dataset.py index 5d0b8fc5..2b37c2f8 100644 --- a/tests/cc/test_cc_dataset.py +++ b/tests/cc/test_cc_dataset.py @@ -5,8 +5,8 @@ from pathlib import Path from tempfile import TemporaryDirectory import pytest - import tests.data.cc.dataset + from sec_certs import constants from sec_certs.dataset import CCDataset from sec_certs.sample.cc import CCCertificate diff --git a/tests/cc/test_cc_maintenance_updates.py b/tests/cc/test_cc_maintenance_updates.py index 833391ef..254df45c 100644 --- a/tests/cc/test_cc_maintenance_updates.py +++ b/tests/cc/test_cc_maintenance_updates.py @@ -2,8 +2,8 @@ import json from pathlib import Path import pytest - import tests.data.cc.dataset + from sec_certs.dataset import CCDataset, CCDatasetMaintenanceUpdates from sec_certs.sample.cc_maintenance_update import CCMaintenanceUpdate @@ -21,7 +21,7 @@ def cc_dset(data_dir: Path) -> CCDataset: @pytest.fixture def mu_dset(data_dir: Path, tmp_path_factory) -> CCDatasetMaintenanceUpdates: tmp_dir = tmp_path_factory.mktemp("mu_dset") - dset = CCDatasetMaintenanceUpdates.from_json(data_dir / "auxillary_datasets/maintenances/maintenance_updates.json") + dset = CCDatasetMaintenanceUpdates.from_json(data_dir / "auxiliary_datasets/maintenances/maintenance_updates.json") dset.copy_dataset(tmp_dir) return dset @@ -33,7 +33,7 @@ def test_methods_not_meant_to_be_implemented(): with pytest.raises(NotImplementedError): dset._compute_heuristics() with pytest.raises(NotImplementedError): - dset.process_auxillary_datasets() + dset.process_auxiliary_datasets() with pytest.raises(NotImplementedError): dset.compute_related_cves() with pytest.raises(NotImplementedError): @@ -58,7 +58,7 @@ def test_dataset_to_json(mu_dset: CCDatasetMaintenanceUpdates, data_dir: Path, t with (tmp_path / "dset.json").open("r") as handle: data = json.load(handle) - with (data_dir / "auxillary_datasets/maintenances/maintenance_updates.json").open("r") as handle: + with (data_dir / "auxiliary_datasets/maintenances/maintenance_updates.json").open("r") as handle: template_data = json.load(handle) del template_data["timestamp"] @@ -68,7 +68,7 @@ def test_dataset_to_json(mu_dset: CCDatasetMaintenanceUpdates, data_dir: Path, t def test_dataset_from_json(mu_dset: CCDatasetMaintenanceUpdates, data_dir: Path): assert mu_dset == CCDatasetMaintenanceUpdates.from_json( - data_dir / "auxillary_datasets/maintenances/maintenance_updates.json" + data_dir / "auxiliary_datasets/maintenances/maintenance_updates.json" ) diff --git a/tests/data/cc/analysis/auxillary_datasets/cpe_dataset.json b/tests/data/cc/analysis/auxiliary_datasets/cpe_dataset.json index 559a3b57..559a3b57 100644 --- a/tests/data/cc/analysis/auxillary_datasets/cpe_dataset.json +++ b/tests/data/cc/analysis/auxiliary_datasets/cpe_dataset.json diff --git a/tests/data/cc/analysis/auxillary_datasets/cve_dataset.json b/tests/data/cc/analysis/auxiliary_datasets/cve_dataset.json index 4caf45d1..4caf45d1 100644 --- a/tests/data/cc/analysis/auxillary_datasets/cve_dataset.json +++ b/tests/data/cc/analysis/auxiliary_datasets/cve_dataset.json diff --git a/tests/data/cc/analysis/auxillary_datasets/cve_dset_with_cpe_configs.json b/tests/data/cc/analysis/auxiliary_datasets/cve_dset_with_cpe_configs.json index 32d188f5..32d188f5 100644 --- a/tests/data/cc/analysis/auxillary_datasets/cve_dset_with_cpe_configs.json +++ b/tests/data/cc/analysis/auxiliary_datasets/cve_dset_with_cpe_configs.json diff --git a/tests/data/cc/analysis/cc_full_dataset.json b/tests/data/cc/analysis/cc_full_dataset.json index d12a9456..05e75c55 100644 --- a/tests/data/cc/analysis/cc_full_dataset.json +++ b/tests/data/cc/analysis/cc_full_dataset.json @@ -5,7 +5,7 @@ "meta_sources_parsed": true, "artifacts_downloaded": true, "pdfs_converted": true, - "auxillary_datasets_processed": true, + "auxiliary_datasets_processed": true, "certs_analyzed": false }, "timestamp": "2022-11-04 16:28:04.282938", diff --git a/tests/data/cc/analysis/vulnerable_dataset.json b/tests/data/cc/analysis/vulnerable_dataset.json index d433fac1..32ec6ce7 100644 --- a/tests/data/cc/analysis/vulnerable_dataset.json +++ b/tests/data/cc/analysis/vulnerable_dataset.json @@ -5,7 +5,7 @@ "meta_sources_parsed": true, "artifacts_downloaded": false, "pdfs_converted": false, - "auxillary_datasets_processed": true, + "auxiliary_datasets_processed": true, "certs_analyzed": false }, "timestamp": "2021-04-16 15:05:18.386794", diff --git a/tests/data/cc/dataset/auxillary_datasets/maintenances/maintenance_updates.json b/tests/data/cc/dataset/auxiliary_datasets/maintenances/maintenance_updates.json index 21567fe4..fd21471b 100644 --- a/tests/data/cc/dataset/auxillary_datasets/maintenances/maintenance_updates.json +++ b/tests/data/cc/dataset/auxiliary_datasets/maintenances/maintenance_updates.json @@ -5,7 +5,7 @@ "meta_sources_parsed": true, "artifacts_downloaded": true, "pdfs_converted": false, - "auxillary_datasets_processed": false, + "auxiliary_datasets_processed": false, "certs_analyzed": false }, "timestamp": "2022-11-10 13:44:35.171285", diff --git a/tests/data/cc/dataset/toy_dataset.json b/tests/data/cc/dataset/toy_dataset.json index bd674311..dec802f7 100644 --- a/tests/data/cc/dataset/toy_dataset.json +++ b/tests/data/cc/dataset/toy_dataset.json @@ -5,7 +5,7 @@ "meta_sources_parsed": true, "artifacts_downloaded": false, "pdfs_converted": false, - "auxillary_datasets_processed": false, + "auxiliary_datasets_processed": false, "certs_analyzed": false }, "timestamp": "2020-11-16 17:04:14.770153", diff --git a/tests/data/fips/certificate/fictional_cert.json b/tests/data/fips/certificate/fictional_cert.json index a1dbec54..9ec36238 100644 --- a/tests/data/fips/certificate/fictional_cert.json +++ b/tests/data/fips/certificate/fictional_cert.json @@ -1,7 +1,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "184097a88a9b4ad9", - "cert_id": "3518", + "cert_id": 3518, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, diff --git a/tests/data/fips/dataset/toy_dataset.json b/tests/data/fips/dataset/toy_dataset.json index 37853ff9..97edf45e 100644 --- a/tests/data/fips/dataset/toy_dataset.json +++ b/tests/data/fips/dataset/toy_dataset.json @@ -5,7 +5,7 @@ "meta_sources_parsed": true, "artifacts_downloaded": true, "pdfs_converted": true, - "auxillary_datasets_processed": false, + "auxiliary_datasets_processed": false, "certs_analyzed": false }, "timestamp": "2022-11-30 16:38:51.953055", @@ -17,7 +17,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "69d9200c309f5f97", - "cert_id": "2590", + "cert_id": 2590, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -101,7 +101,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "3b05cf67849835e3", - "cert_id": "2997", + "cert_id": 2997, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -185,7 +185,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "618102f275d5649a", - "cert_id": "3495", + "cert_id": 3495, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -269,7 +269,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "5b00a7bb92c1cb19", - "cert_id": "2721", + "cert_id": 2721, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -353,7 +353,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "e1ff7d9997726782", - "cert_id": "3090", + "cert_id": 3090, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -437,7 +437,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "ed16d272044ed81f", - "cert_id": "2860", + "cert_id": 2860, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -521,7 +521,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "73e7f3f802b0e919", - "cert_id": "3176", + "cert_id": 3176, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -605,7 +605,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "756a6524cdb2d4ea", - "cert_id": "3850", + "cert_id": 3850, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -689,7 +689,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "0e8b7a7f79b3098b", - "cert_id": "2665", + "cert_id": 2665, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -773,7 +773,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "f7df34ce0a0ad316", - "cert_id": "3093", + "cert_id": 3093, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -857,7 +857,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "0df59fd6c41cadd2", - "cert_id": "3711", + "cert_id": 3711, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -941,7 +941,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "24a05f4d1305d667", - "cert_id": "3493", + "cert_id": 3493, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -1025,7 +1025,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "51c94a510b50e68f", - "cert_id": "3141", + "cert_id": 3141, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -1109,7 +1109,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "75ca28395bfc9ad1", - "cert_id": "2630", + "cert_id": 2630, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -1193,7 +1193,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "cd0666cdd7ce0244", - "cert_id": "3095", + "cert_id": 3095, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -1277,7 +1277,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "ceab64951a30f684", - "cert_id": "3197", + "cert_id": 3197, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -1361,7 +1361,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "0ab77c56eece2d24", - "cert_id": "3651", + "cert_id": 3651, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -1445,7 +1445,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "9ca7b8be590113b8", - "cert_id": "2711", + "cert_id": 2711, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -1529,7 +1529,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "184097a88a9b4ad9", - "cert_id": "3518", + "cert_id": 3518, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -1613,7 +1613,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "c333a75353784177", - "cert_id": "2779", + "cert_id": 2779, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -1697,7 +1697,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "ad1e075215267a28", - "cert_id": "2441", + "cert_id": 2441, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, @@ -1781,7 +1781,7 @@ { "_type": "sec_certs.sample.fips.FIPSCertificate", "dgst": "2aec3694418f35d8", - "cert_id": "3488", + "cert_id": 3488, "web_data": { "_type": "sec_certs.sample.fips.FIPSCertificate.WebData", "module_name": null, diff --git a/tests/fips/test_fips_algorithm_dataset.py b/tests/fips/test_fips_algorithm_dataset.py index 88016f4f..1d45e67c 100644 --- a/tests/fips/test_fips_algorithm_dataset.py +++ b/tests/fips/test_fips_algorithm_dataset.py @@ -4,8 +4,8 @@ from pathlib import Path from typing import Any import pytest - import tests.data.fips.dataset + from sec_certs.dataset.fips_algorithm import FIPSAlgorithmDataset from sec_certs.sample.fips_algorithm import FIPSAlgorithm from sec_certs.serialization.json import SerializationError diff --git a/tests/fips/test_fips_analysis.py b/tests/fips/test_fips_analysis.py index ffd78a3f..6c5b032e 100644 --- a/tests/fips/test_fips_analysis.py +++ b/tests/fips/test_fips_analysis.py @@ -3,8 +3,8 @@ from __future__ import annotations from pathlib import Path import pytest - import tests.data.fips.dataset + from sec_certs.dataset import CPEDataset, CVEDataset from sec_certs.dataset.fips import FIPSDataset from sec_certs.sample.cpe import CPE, CPEConfiguration @@ -147,8 +147,8 @@ def processed_dataset( toy_static_dataset.extract_data() toy_static_dataset._compute_references(keep_unknowns=True) - toy_static_dataset.auxillary_datasets.cpe_dset = cpe_dataset - toy_static_dataset.auxillary_datasets.cve_dset = cve_dataset + toy_static_dataset.auxiliary_datasets.cpe_dset = cpe_dataset + toy_static_dataset.auxiliary_datasets.cve_dset = cve_dataset toy_static_dataset.compute_cpe_heuristics() toy_static_dataset.compute_related_cves() toy_static_dataset._compute_transitive_vulnerabilities() @@ -271,7 +271,7 @@ def test_find_related_cves_for_cpe_configuration( cve_dataset.cves = {ibm_xss_cve.cve_id: ibm_xss_cve} cert = processed_dataset["2441"] cert.heuristics.cpe_matches = {cve.uri for cve in cpes_ibm_websphere_app_with_platform} - processed_dataset.auxillary_datasets.cve_dset = cve_dataset + processed_dataset.auxiliary_datasets.cve_dset = cve_dataset processed_dataset.compute_related_cves() assert {ibm_xss_cve.cve_id} == cert.heuristics.related_cves diff --git a/tests/fips/test_fips_certificate.py b/tests/fips/test_fips_certificate.py index b612834c..8f68238e 100644 --- a/tests/fips/test_fips_certificate.py +++ b/tests/fips/test_fips_certificate.py @@ -3,9 +3,9 @@ import shutil from pathlib import Path import pytest - import tests.data.fips.certificate import tests.data.fips.dataset + from sec_certs.dataset.fips import FIPSDataset from sec_certs.sample.fips import FIPSCertificate diff --git a/tests/fips/test_fips_dataset.py b/tests/fips/test_fips_dataset.py index b5f09aa9..99dc57af 100644 --- a/tests/fips/test_fips_dataset.py +++ b/tests/fips/test_fips_dataset.py @@ -4,9 +4,9 @@ from pathlib import Path from tempfile import TemporaryDirectory import pytest - -import sec_certs.constants as constants import tests.data.fips.dataset + +from sec_certs import constants from sec_certs.dataset.fips import FIPSDataset from sec_certs.sample.fips import FIPSCertificate @@ -70,6 +70,7 @@ def test_build_dataset(data_dir: Path, toy_dataset: FIPSDataset): def test_download_meta_html_files(): with TemporaryDirectory() as tmp_dir: dset = FIPSDataset(root_dir=Path(tmp_dir)) + dset.web_dir.mkdir() dset._download_html_resources() assert (dset.web_dir / "fips_modules_active.html").exists() diff --git a/tests/fips/test_fips_iut.py b/tests/fips/test_fips_iut.py index 5a478a20..1dca086c 100644 --- a/tests/fips/test_fips_iut.py +++ b/tests/fips/test_fips_iut.py @@ -1,8 +1,8 @@ from pathlib import Path import pytest - import tests.data.fips.iut + from sec_certs.dataset import IUTDataset from sec_certs.sample import IUTSnapshot diff --git a/tests/fips/test_fips_mip.py b/tests/fips/test_fips_mip.py index 8748bf23..4918a4c6 100644 --- a/tests/fips/test_fips_mip.py +++ b/tests/fips/test_fips_mip.py @@ -1,8 +1,8 @@ from pathlib import Path import pytest - import tests.data.fips.mip + from sec_certs.dataset import MIPDataset from sec_certs.sample import MIPSnapshot diff --git a/tests/test_common.py b/tests/test_common.py index d5e62cc4..fa7a3775 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -6,4 +6,4 @@ def test_rules(): assert "fips_cert_id" in fips_rules for rule_group in rules: if rule_group not in ("cc_rules", "fips_rules"): - assert rule_group in cc_rules.keys() or rule_group in fips_rules.keys() + assert rule_group in cc_rules or rule_group in fips_rules diff --git a/tests/test_cpe.py b/tests/test_cpe.py index 3be2c1a6..9cee5459 100644 --- a/tests/test_cpe.py +++ b/tests/test_cpe.py @@ -5,7 +5,7 @@ from typing import Any import pytest -import tests.data.cc.analysis.auxillary_datasets +import tests.data.cc.analysis.auxiliary_datasets from sec_certs import constants from sec_certs.dataset import CPEDataset, CVEDataset from sec_certs.sample import CPE, CPEConfiguration @@ -14,12 +14,12 @@ from sec_certs.serialization.json import SerializationError @pytest.fixture(scope="module") def cpe_dset_path() -> Path: - return Path(tests.data.cc.analysis.auxillary_datasets.__path__[0]) / "cpe_dataset.json" + return Path(tests.data.cc.analysis.auxiliary_datasets.__path__[0]) / "cpe_dataset.json" @pytest.fixture(scope="module") def cve_dset_with_cpe_configs_path() -> Path: - return Path(tests.data.cc.analysis.auxillary_datasets.__path__[0]) / "cve_dset_with_cpe_configs.json" + return Path(tests.data.cc.analysis.auxiliary_datasets.__path__[0]) / "cve_dset_with_cpe_configs.json" @pytest.fixture(scope="module") @@ -145,7 +145,7 @@ def test_to_pandas(cpe_dset: CPEDataset): def test_serialization_missing_path(): - dummy_dset = CPEDataset(False, dict()) + dummy_dset = CPEDataset(False, {}) with pytest.raises(SerializationError): dummy_dset.to_json() diff --git a/tests/test_cve.py b/tests/test_cve.py index 20c04147..0382974a 100644 --- a/tests/test_cve.py +++ b/tests/test_cve.py @@ -5,7 +5,7 @@ from typing import Any import pytest -import tests.data.cc.analysis.auxillary_datasets +import tests.data.cc.analysis.auxiliary_datasets from sec_certs.dataset import CVEDataset from sec_certs.sample import CVE from sec_certs.sample.cpe import CPE @@ -24,7 +24,7 @@ def test_from_web(): @pytest.fixture(scope="module") def cve_dataset_path() -> Path: - return Path(tests.data.cc.analysis.auxillary_datasets.__path__[0]) / "cve_dataset.json" + return Path(tests.data.cc.analysis.auxiliary_datasets.__path__[0]) / "cve_dataset.json" @pytest.fixture(scope="module") |
