classifyre-cli 0.4.74__tar.gz → 0.4.75__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/.turbo/turbo-build.log +1 -1
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/PKG-INFO +1 -1
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/package.json +1 -1
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/pyproject.toml +1 -1
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/atlassian_common.py +3 -2
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/email/source.py +2 -2
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/google_workspace/source.py +2 -2
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/microsoft_365/source.py +2 -2
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/notion/client.py +3 -1
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/object_storage/base.py +8 -4
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/file_parser.py +52 -10
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/utils/test_file_parser.py +73 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/uv.lock +2 -2
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/.gitignore +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/.python-version +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/README.md +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/main.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/scripts/generate_models.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/config.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/base.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/broken_links/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/broken_links/detector.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/config.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/content/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/detector.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/extractor.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/runners/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/runners/_base.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/runners/_factory.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/runners/_gliner2.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/runners/_image_classification.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/runners/_llm.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/runners/_object_detection.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/runners/_regex.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/runners/_text_classification.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/trainer.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/dependencies.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/pii/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/pii/detector.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/secrets/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/secrets/detector.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/threat/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/threat/code_security_detector.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/threat/yara_detector.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/file_evaluation/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/file_evaluation/runner.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/main.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/models/generated_detectors.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/models/generated_input.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/models/generated_single_asset_scan_results.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/outputs/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/outputs/base.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/outputs/console.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/outputs/factory.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/outputs/file.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/outputs/rest.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/pipeline/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/pipeline/content_provider.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/pipeline/detector_pipeline.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/pipeline/parsed_content_provider.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/pipeline/text_artifact.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/pipeline/worker_pool.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/asset_metadata.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/azure_blob_storage/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/azure_blob_storage/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/base.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/confluence/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/confluence/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/databricks/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/databricks/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/delta_lake/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/delta_lake/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/dependencies.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/dropbox/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/dropbox/auth.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/dropbox/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/elasticsearch/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/elasticsearch/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/email/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/google_cloud_storage/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/google_cloud_storage/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/google_workspace/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/hive/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/hive/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/iceberg/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/iceberg/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/jira/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/jira/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/kafka/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/kafka/rest.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/kafka/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/lakehouse_base.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/local_folder/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/local_folder/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/meilisearch/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/meilisearch/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/microsoft_365/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/mongodb/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/mongodb/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/mssql/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/mssql/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/mysql/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/mysql/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/neo4j/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/neo4j/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/notion/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/notion/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/opensearch/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/opensearch/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/oracle/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/oracle/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/postgresql/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/postgresql/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/powerbi/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/powerbi/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/recipe_normalizer.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/s3_client.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/s3_compatible_storage/README.md +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/s3_compatible_storage/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/s3_compatible_storage/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/sandbox/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/sandbox/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/search_engine_base.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/servicedesk/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/servicedesk/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/slack/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/slack/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/snowflake/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/snowflake/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/sqlite/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/sqlite/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/tableau/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/tableau/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/tabular_base.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/tabular_utils.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/wordpress/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/wordpress/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/youtube/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/youtube/source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/telemetry.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/archive_extraction.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/content_extraction.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/dependency_groups.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/embedded_images.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/file_metadata.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/file_to_images.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/hashing.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/legacy_office.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/resources.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/transcription.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/uv_sync.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/validation.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/utils/video_processing.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/_lakehouse_fakes.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/conftest.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/broken_links/test_broken_links_detector.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/conftest.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/content/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/custom/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/custom/conftest.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/custom/test_gliner2_classification.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/custom/test_invoice_extraction.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/custom/test_llm_runner.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/custom/test_pipeline_integration.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/custom/test_regex_runner.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/custom/test_runner_hardening.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/custom/test_transformer_runners.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/pii/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/pii/conftest.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/pii/sample_invoice.pdf +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/pii/test_pii_chunking.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/pii/test_pii_detector.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/pii/test_pii_detector_extended.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/pii/test_pii_regional_entities.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/pii/test_pii_severity.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/secrets/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/secrets/test_secrets_detector.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/secrets/test_secrets_detector_extended.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/test_base_detector.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/test_custom_detector_examples_runtime.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/test_detector_catalog_commercial.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/test_detector_pipeline_types.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/test_detector_schema_examples.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/test_detector_types.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/test_phase2_detectors.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/test_registry.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/threat/__init__.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/threat/test_code_security_detector.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/detectors/threat/test_yara_detector.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/integration/test_wordpress_broken_links_detector.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/integration/test_wordpress_links_assets.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/pipeline/test_detector_outcomes.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/pipeline/test_detector_pipeline.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/pipeline/test_worker_pool.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_assets_metadata_catalog.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_azure_blob_storage_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_base_source_attachment.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_base_source_sampling.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_config.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_confluence_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_custom_extractor.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_databricks_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_delta_lake_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_dependency_groups.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_dropbox_auth_command.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_dropbox_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_elasticsearch_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_email_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_file_evaluation_runner.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_google_cloud_storage_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_google_workspace_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_hashing.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_hive_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_iceberg_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_jira_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_kafka_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_local_folder_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_main.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_meilisearch_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_microsoft_365_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_mongodb_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_mssql_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_mysql_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_neo4j_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_notion_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_opensearch_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_oracle_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_outputs.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_postgresql_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_powerbi_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_recipe_normalizer.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_s3_compatible_storage_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_sampling_automatic.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_sandbox_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_servicedesk_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_slack_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_snowflake_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_source_dependency_groups.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_source_strategy_conformance.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_sqlite_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_tableau_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_tabular_automatic_sampling.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_tabular_utils.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_uv_sync.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_wordpress_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_youtube_source.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/test_youtube_source_integration.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/utils/test_archive_extraction.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/utils/test_content_extraction.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/utils/test_embedded_images.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/utils/test_file_metadata.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/utils/test_file_to_images.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/utils/test_legacy_office.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/utils/test_transcription.py +0 -0
- {classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/tests/utils/test_video_processing.py +0 -0
|
@@ -11,6 +11,7 @@ from urllib.parse import urljoin, urlsplit, urlunsplit
|
|
|
11
11
|
|
|
12
12
|
import requests
|
|
13
13
|
|
|
14
|
+
from ..utils.file_parser import normalize_mime_type
|
|
14
15
|
from ..utils.hashing import normalize_http_url
|
|
15
16
|
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
@@ -86,7 +87,7 @@ def extract_urls_from_text(text: str) -> list[str]:
|
|
|
86
87
|
|
|
87
88
|
|
|
88
89
|
def is_tabular_mime_type(mime_type: str) -> bool:
|
|
89
|
-
normalized = mime_type
|
|
90
|
+
normalized = normalize_mime_type(mime_type)
|
|
90
91
|
return normalized in TABULAR_MIME_TYPES
|
|
91
92
|
|
|
92
93
|
|
|
@@ -206,7 +207,7 @@ class AtlassianCloudClient:
|
|
|
206
207
|
for chunk in response.iter_content(chunk_size=8192):
|
|
207
208
|
if chunk:
|
|
208
209
|
chunks.append(chunk)
|
|
209
|
-
mime = response.headers.get("Content-Type", "")
|
|
210
|
+
mime = normalize_mime_type(response.headers.get("Content-Type", ""))
|
|
210
211
|
return b"".join(chunks), mime
|
|
211
212
|
|
|
212
213
|
def iter_confluence_results(
|
|
@@ -25,7 +25,7 @@ from ...models.generated_single_asset_scan_results import (
|
|
|
25
25
|
)
|
|
26
26
|
from ...utils.content_extraction import html_to_text
|
|
27
27
|
from ...utils.file_metadata import extract_file_metadata
|
|
28
|
-
from ...utils.file_parser import resolve_mime_type
|
|
28
|
+
from ...utils.file_parser import normalize_mime_type, resolve_mime_type
|
|
29
29
|
from ...utils.hashing import hash_id
|
|
30
30
|
from ..base import BaseSource
|
|
31
31
|
from ..dependencies import require_module
|
|
@@ -488,7 +488,7 @@ class EmailSource(BaseSource):
|
|
|
488
488
|
|
|
489
489
|
@staticmethod
|
|
490
490
|
def _asset_type_from_mime(mime: str) -> OutputAssetType:
|
|
491
|
-
normalized = (mime
|
|
491
|
+
normalized = normalize_mime_type(mime)
|
|
492
492
|
if normalized.startswith("image/"):
|
|
493
493
|
return OutputAssetType.IMAGE
|
|
494
494
|
if normalized.startswith("audio/"):
|
|
@@ -28,7 +28,7 @@ from ...models.generated_single_asset_scan_results import (
|
|
|
28
28
|
SingleAssetScanResults,
|
|
29
29
|
)
|
|
30
30
|
from ...utils.file_metadata import extract_file_metadata
|
|
31
|
-
from ...utils.file_parser import resolve_mime_type
|
|
31
|
+
from ...utils.file_parser import normalize_mime_type, resolve_mime_type
|
|
32
32
|
from ...utils.hashing import hash_id
|
|
33
33
|
from ..base import BaseSource
|
|
34
34
|
from ..dependencies import require_module
|
|
@@ -572,7 +572,7 @@ class GoogleWorkspaceSource(BaseSource):
|
|
|
572
572
|
# -- Asset construction --
|
|
573
573
|
|
|
574
574
|
def _asset_type_from_mime_or_key(self, mime_type: str | None, key: str) -> OutputAssetType:
|
|
575
|
-
normalized_mime = (mime_type
|
|
575
|
+
normalized_mime = normalize_mime_type(mime_type)
|
|
576
576
|
extension = PurePosixPath(key).suffix.lower()
|
|
577
577
|
|
|
578
578
|
if normalized_mime in _TABULAR_MIME_TYPES:
|
|
@@ -32,7 +32,7 @@ from ...models.generated_single_asset_scan_results import (
|
|
|
32
32
|
SingleAssetScanResults,
|
|
33
33
|
)
|
|
34
34
|
from ...utils.file_metadata import extract_file_metadata
|
|
35
|
-
from ...utils.file_parser import resolve_mime_type
|
|
35
|
+
from ...utils.file_parser import normalize_mime_type, resolve_mime_type
|
|
36
36
|
from ...utils.hashing import hash_id
|
|
37
37
|
from ..base import BaseSource
|
|
38
38
|
from ..dependencies import require_module
|
|
@@ -679,7 +679,7 @@ class Microsoft365Source(BaseSource):
|
|
|
679
679
|
# -- Asset construction --
|
|
680
680
|
|
|
681
681
|
def _asset_type_from_mime_or_key(self, mime_type: str | None, key: str) -> OutputAssetType:
|
|
682
|
-
normalized_mime = (mime_type
|
|
682
|
+
normalized_mime = normalize_mime_type(mime_type)
|
|
683
683
|
extension = PurePosixPath(key).suffix.lower()
|
|
684
684
|
|
|
685
685
|
if normalized_mime in _TABULAR_MIME_TYPES:
|
|
@@ -6,6 +6,8 @@ from typing import Any
|
|
|
6
6
|
|
|
7
7
|
import requests
|
|
8
8
|
|
|
9
|
+
from ...utils.file_parser import normalize_mime_type
|
|
10
|
+
|
|
9
11
|
logger = logging.getLogger(__name__)
|
|
10
12
|
|
|
11
13
|
NOTION_API_BASE = "https://api.notion.com/v1"
|
|
@@ -154,7 +156,7 @@ class NotionClient:
|
|
|
154
156
|
for chunk in response.iter_content(chunk_size=8192):
|
|
155
157
|
if chunk:
|
|
156
158
|
chunks.append(chunk)
|
|
157
|
-
mime = response.headers.get("Content-Type", "")
|
|
159
|
+
mime = normalize_mime_type(response.headers.get("Content-Type", ""))
|
|
158
160
|
return b"".join(chunks), mime
|
|
159
161
|
|
|
160
162
|
def get_page(self, page_id: str) -> dict[str, Any]:
|
|
@@ -25,7 +25,11 @@ from ...models.generated_single_asset_scan_results import (
|
|
|
25
25
|
from ...utils.archive_extraction import ArchiveMember, is_archive_mime, iter_archive_members
|
|
26
26
|
from ...utils.embedded_images import EmbeddedImage, has_embedded_images, iter_embedded_images
|
|
27
27
|
from ...utils.file_metadata import extract_file_metadata
|
|
28
|
-
from ...utils.file_parser import
|
|
28
|
+
from ...utils.file_parser import (
|
|
29
|
+
infer_mime_type_from_file_name,
|
|
30
|
+
normalize_mime_type,
|
|
31
|
+
resolve_mime_type,
|
|
32
|
+
)
|
|
29
33
|
from ...utils.hashing import hash_id, unhash_id
|
|
30
34
|
from ..base import BaseSource
|
|
31
35
|
from ..dependencies import require_module
|
|
@@ -325,7 +329,7 @@ class ObjectStorageSourceBase(BaseSource, ABC):
|
|
|
325
329
|
return ref.key
|
|
326
330
|
|
|
327
331
|
def _asset_type_from_mime_or_key(self, mime_type: str | None, key: str) -> OutputAssetType:
|
|
328
|
-
normalized_mime = (mime_type
|
|
332
|
+
normalized_mime = normalize_mime_type(mime_type)
|
|
329
333
|
extension = self._file_extension(key)
|
|
330
334
|
|
|
331
335
|
if normalized_mime in _TABULAR_MIME_TYPES:
|
|
@@ -397,7 +401,7 @@ class ObjectStorageSourceBase(BaseSource, ABC):
|
|
|
397
401
|
|
|
398
402
|
def _build_snapshot(self, ref: ObjectRef) -> ContentSnapshot:
|
|
399
403
|
if self._discovery_only or not self._include_content_preview():
|
|
400
|
-
mime = (ref.content_type_hint
|
|
404
|
+
mime = normalize_mime_type(ref.content_type_hint)
|
|
401
405
|
if not mime:
|
|
402
406
|
mime = infer_mime_type_from_file_name(self._object_file_name(ref))
|
|
403
407
|
return ContentSnapshot(
|
|
@@ -426,7 +430,7 @@ class ObjectStorageSourceBase(BaseSource, ABC):
|
|
|
426
430
|
declared_mime_type=content_type_hint or ref.content_type_hint or "",
|
|
427
431
|
file_name=self._object_file_name(ref),
|
|
428
432
|
)
|
|
429
|
-
normalized_mime = mime_type
|
|
433
|
+
normalized_mime = normalize_mime_type(mime_type)
|
|
430
434
|
|
|
431
435
|
# Images and audio/video are extractable automatically. Opaque binaries
|
|
432
436
|
# remain available to binary detectors but have no text page stream.
|
|
@@ -61,6 +61,37 @@ class ParsedBytes:
|
|
|
61
61
|
parse_error: str | None = None
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
OCTET_STREAM = "application/octet-stream"
|
|
65
|
+
|
|
66
|
+
# Spellings of "I don't know what these bytes are". Only the first is the
|
|
67
|
+
# registered type, but object stores are inconsistent: S3-compatible services
|
|
68
|
+
# (Backblaze B2 among them) label every upload `binary/octet-stream`. Because
|
|
69
|
+
# that is not the IANA spelling, treating it as a *real* content type made it
|
|
70
|
+
# win over magic-byte detection and filename inference — so every object served
|
|
71
|
+
# that way skipped MIME resolution entirely, matched no branch in extract_text,
|
|
72
|
+
# and returned no text AND no error. Assets were then recorded as scanned and
|
|
73
|
+
# empty, which is indistinguishable from a genuinely empty file.
|
|
74
|
+
_GENERIC_BINARY_MIME_TYPES = frozenset(
|
|
75
|
+
{
|
|
76
|
+
OCTET_STREAM,
|
|
77
|
+
"binary/octet-stream",
|
|
78
|
+
"application/binary",
|
|
79
|
+
"application/unknown",
|
|
80
|
+
"unknown/unknown",
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _canonical_mime_type(mime_type: str) -> str:
|
|
86
|
+
"""Collapse every "unknown bytes" spelling onto the registered one.
|
|
87
|
+
|
|
88
|
+
Downstream code compares against ``application/octet-stream`` in a dozen
|
|
89
|
+
places (is_binary, archive handling, detector content-type matching); mapping
|
|
90
|
+
aliases here means none of those have to know the alias list.
|
|
91
|
+
"""
|
|
92
|
+
return OCTET_STREAM if mime_type in _GENERIC_BINARY_MIME_TYPES else mime_type
|
|
93
|
+
|
|
94
|
+
|
|
64
95
|
_TEXT_RAW_MIME_TYPES = {
|
|
65
96
|
"application/json",
|
|
66
97
|
"application/xml",
|
|
@@ -327,10 +358,21 @@ def _require_file_processing(module_name: str) -> object:
|
|
|
327
358
|
return require_module(module_name, "file parser", ["file-processing"])
|
|
328
359
|
|
|
329
360
|
|
|
330
|
-
def
|
|
361
|
+
def normalize_mime_type(mime_type: str | None) -> str:
|
|
362
|
+
"""Strip parameters, lower-case, and collapse "unknown bytes" aliases.
|
|
363
|
+
|
|
364
|
+
The single place MIME strings are normalized. Sources must use this rather
|
|
365
|
+
than an inline ``split(";")[0].strip().lower()``: that idiom looks equivalent
|
|
366
|
+
but skips the alias collapsing, which is exactly how `binary/octet-stream`
|
|
367
|
+
from S3-compatible stores slipped through as a real content type.
|
|
368
|
+
"""
|
|
331
369
|
if not mime_type:
|
|
332
370
|
return ""
|
|
333
|
-
return str(mime_type).split(";", 1)[0].strip().lower()
|
|
371
|
+
return _canonical_mime_type(str(mime_type).split(";", 1)[0].strip().lower())
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
# Internal alias kept so the many call sites in this module stay unchanged.
|
|
375
|
+
_normalize_mime_type = normalize_mime_type
|
|
334
376
|
|
|
335
377
|
|
|
336
378
|
def _file_extension(file_name: str) -> str:
|
|
@@ -357,7 +399,7 @@ def normalize_detected_mime_type(detected_mime_type: str, file_name: str) -> str
|
|
|
357
399
|
mime = _normalize_mime_type(detected_mime_type)
|
|
358
400
|
inferred_mime = infer_mime_type_from_file_name(file_name)
|
|
359
401
|
|
|
360
|
-
if not mime or mime ==
|
|
402
|
+
if not mime or mime == OCTET_STREAM:
|
|
361
403
|
return inferred_mime
|
|
362
404
|
|
|
363
405
|
if mime == "text/plain" and inferred_mime in _TABULAR_MIME_TYPES:
|
|
@@ -1015,17 +1057,17 @@ def resolve_mime_type(
|
|
|
1015
1057
|
detected_mime = _normalize_mime_type(detect_mime_type(file_bytes))
|
|
1016
1058
|
inferred_mime = infer_mime_type_from_file_name(file_name)
|
|
1017
1059
|
|
|
1018
|
-
if declared_mime and declared_mime !=
|
|
1060
|
+
if declared_mime and declared_mime != OCTET_STREAM:
|
|
1019
1061
|
mime_type = declared_mime
|
|
1020
|
-
elif detected_mime and detected_mime !=
|
|
1062
|
+
elif detected_mime and detected_mime != OCTET_STREAM:
|
|
1021
1063
|
mime_type = detected_mime
|
|
1022
|
-
elif inferred_mime and inferred_mime !=
|
|
1064
|
+
elif inferred_mime and inferred_mime != OCTET_STREAM:
|
|
1023
1065
|
mime_type = inferred_mime
|
|
1024
1066
|
else:
|
|
1025
|
-
mime_type = declared_mime or detected_mime or inferred_mime or
|
|
1067
|
+
mime_type = declared_mime or detected_mime or inferred_mime or OCTET_STREAM
|
|
1026
1068
|
|
|
1027
1069
|
mime_type = normalize_detected_mime_type(mime_type, file_name)
|
|
1028
|
-
if mime_type ==
|
|
1070
|
+
if mime_type == OCTET_STREAM and inferred_mime != OCTET_STREAM:
|
|
1029
1071
|
mime_type = inferred_mime
|
|
1030
1072
|
|
|
1031
1073
|
# A text-like claim (declared upload header or file extension) must survive
|
|
@@ -1033,10 +1075,10 @@ def resolve_mime_type(
|
|
|
1033
1075
|
# control-character garbage that poisons every text consumer downstream.
|
|
1034
1076
|
if (
|
|
1035
1077
|
file_bytes
|
|
1036
|
-
and detected_mime ==
|
|
1078
|
+
and detected_mime == OCTET_STREAM
|
|
1037
1079
|
and (mime_type.startswith("text/") or mime_type in ("application/json", "application/xml"))
|
|
1038
1080
|
):
|
|
1039
|
-
return
|
|
1081
|
+
return OCTET_STREAM
|
|
1040
1082
|
|
|
1041
1083
|
return mime_type
|
|
1042
1084
|
|
|
@@ -665,6 +665,79 @@ class TestOleMimeResolution:
|
|
|
665
665
|
assert resolve_mime_type(ole, file_name="blob") == "application/x-ole-storage"
|
|
666
666
|
|
|
667
667
|
|
|
668
|
+
class TestGenericBinaryMimeAliases:
|
|
669
|
+
"""S3-compatible stores declare `binary/octet-stream`, not the IANA spelling.
|
|
670
|
+
|
|
671
|
+
Treating that as a real content type let it outrank magic bytes and the file
|
|
672
|
+
extension, so every object from Backblaze B2 resolved to a type no extractor
|
|
673
|
+
handles — producing no text AND no error, which recorded the asset as
|
|
674
|
+
scanned-and-empty. Covers all formats, not just legacy Office.
|
|
675
|
+
"""
|
|
676
|
+
|
|
677
|
+
OLE = b"\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1" + b"\x00" * 512
|
|
678
|
+
|
|
679
|
+
@pytest.mark.parametrize(
|
|
680
|
+
"declared",
|
|
681
|
+
[
|
|
682
|
+
"binary/octet-stream",
|
|
683
|
+
"application/octet-stream",
|
|
684
|
+
"application/binary",
|
|
685
|
+
"application/unknown",
|
|
686
|
+
"unknown/unknown",
|
|
687
|
+
"BINARY/OCTET-STREAM",
|
|
688
|
+
"binary/octet-stream; charset=binary",
|
|
689
|
+
"",
|
|
690
|
+
],
|
|
691
|
+
)
|
|
692
|
+
def test_generic_declaration_never_outranks_content(self, declared: str) -> None:
|
|
693
|
+
from src.utils.file_parser import resolve_mime_type
|
|
694
|
+
|
|
695
|
+
assert (
|
|
696
|
+
resolve_mime_type(self.OLE, declared_mime_type=declared, file_name="Cert.doc")
|
|
697
|
+
== "application/msword"
|
|
698
|
+
)
|
|
699
|
+
|
|
700
|
+
@pytest.mark.parametrize(
|
|
701
|
+
("file_bytes", "file_name", "expected"),
|
|
702
|
+
[
|
|
703
|
+
(b"%PDF-1.4\n" + b"x" * 200, "a.pdf", "application/pdf"),
|
|
704
|
+
(b"\x89PNG\r\n\x1a\n" + b"\x00" * 64, "c.png", "image/png"),
|
|
705
|
+
(OLE, "b.xls", "application/vnd.ms-excel"),
|
|
706
|
+
(OLE, "d.ppt", "application/vnd.ms-powerpoint"),
|
|
707
|
+
],
|
|
708
|
+
)
|
|
709
|
+
def test_every_format_survives_a_generic_declaration(
|
|
710
|
+
self, file_bytes: bytes, file_name: str, expected: str
|
|
711
|
+
) -> None:
|
|
712
|
+
from src.utils.file_parser import resolve_mime_type
|
|
713
|
+
|
|
714
|
+
resolved = resolve_mime_type(
|
|
715
|
+
file_bytes, declared_mime_type="binary/octet-stream", file_name=file_name
|
|
716
|
+
)
|
|
717
|
+
assert resolved == expected
|
|
718
|
+
|
|
719
|
+
def test_normalize_mime_type_collapses_aliases(self) -> None:
|
|
720
|
+
from src.utils.file_parser import normalize_mime_type
|
|
721
|
+
|
|
722
|
+
for alias in ("binary/octet-stream", "application/binary", "unknown/unknown"):
|
|
723
|
+
assert normalize_mime_type(alias) == "application/octet-stream"
|
|
724
|
+
# A real type is left alone.
|
|
725
|
+
assert normalize_mime_type("application/pdf; charset=utf-8") == "application/pdf"
|
|
726
|
+
|
|
727
|
+
def test_real_declared_type_still_wins(self) -> None:
|
|
728
|
+
"""The alias collapsing must not make us ignore genuine declarations."""
|
|
729
|
+
from src.utils.file_parser import resolve_mime_type
|
|
730
|
+
|
|
731
|
+
assert (
|
|
732
|
+
resolve_mime_type(
|
|
733
|
+
b"nothing recognisable here",
|
|
734
|
+
declared_mime_type="text/csv",
|
|
735
|
+
file_name="rows.bin",
|
|
736
|
+
)
|
|
737
|
+
== "text/csv"
|
|
738
|
+
)
|
|
739
|
+
|
|
740
|
+
|
|
668
741
|
class TestRtfExtraction:
|
|
669
742
|
def test_text_extracted(self) -> None:
|
|
670
743
|
pytest.importorskip("striprtf")
|
|
@@ -830,7 +830,7 @@ wheels = [
|
|
|
830
830
|
|
|
831
831
|
[[package]]
|
|
832
832
|
name = "classifyre-cli"
|
|
833
|
-
version = "0.4.
|
|
833
|
+
version = "0.4.75"
|
|
834
834
|
source = { editable = "." }
|
|
835
835
|
dependencies = [
|
|
836
836
|
{ name = "beautifulsoup4" },
|
|
@@ -1355,7 +1355,7 @@ youtube = [
|
|
|
1355
1355
|
|
|
1356
1356
|
[[package]]
|
|
1357
1357
|
name = "classifyre-schemas"
|
|
1358
|
-
version = "0.4.
|
|
1358
|
+
version = "0.4.75"
|
|
1359
1359
|
source = { editable = "../../packages/schemas" }
|
|
1360
1360
|
dependencies = [
|
|
1361
1361
|
{ name = "fastjsonschema" },
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/runners/_object_detection.py
RENAMED
|
File without changes
|
|
File without changes
|
{classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/custom/runners/_text_classification.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/detectors/threat/code_security_detector.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/models/generated_single_asset_scan_results.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{classifyre_cli-0.4.74 → classifyre_cli-0.4.75}/src/sources/google_cloud_storage/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|