classifyre-cli 0.4.78__tar.gz → 0.4.80__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.
Files changed (279) hide show
  1. classifyre_cli-0.4.80/.turbo/turbo-build.log +3 -0
  2. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/PKG-INFO +1 -1
  3. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/package.json +1 -1
  4. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/pyproject.toml +11 -1
  5. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/file_evaluation/runner.py +39 -34
  6. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/main.py +32 -2
  7. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/models/generated_detectors.py +1 -0
  8. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/models/generated_input.py +368 -3
  9. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/models/generated_single_asset_scan_results.py +52 -0
  10. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/outputs/rest.py +22 -5
  11. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/pipeline/parsed_content_provider.py +1 -1
  12. classifyre_cli-0.4.80/src/pipeline/payload_window.py +554 -0
  13. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/pipeline/scan_cache.py +17 -0
  14. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/base.py +67 -8
  15. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/object_storage/base.py +257 -95
  16. classifyre_cli-0.4.80/src/sources/reddit/__init__.py +3 -0
  17. classifyre_cli-0.4.80/src/sources/reddit/source.py +1199 -0
  18. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/youtube/source.py +46 -156
  19. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/dependency_groups.py +1 -0
  20. classifyre_cli-0.4.80/src/utils/embedded_files.py +344 -0
  21. classifyre_cli-0.4.80/src/utils/external_video.py +336 -0
  22. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/file_parser.py +182 -22
  23. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/pipeline/test_detector_pipeline.py +4 -2
  24. classifyre_cli-0.4.80/tests/test_object_storage_download_efficiency.py +267 -0
  25. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_outputs.py +75 -0
  26. classifyre_cli-0.4.80/tests/test_payload_window.py +517 -0
  27. classifyre_cli-0.4.80/tests/test_payload_window_parquet.py +296 -0
  28. classifyre_cli-0.4.80/tests/test_reddit_source.py +762 -0
  29. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_s3_compatible_storage_source.py +151 -10
  30. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_scan_cache.py +122 -0
  31. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_source_strategy_conformance.py +39 -0
  32. classifyre_cli-0.4.80/tests/utils/test_embedded_files.py +246 -0
  33. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/uv.lock +100 -46
  34. classifyre_cli-0.4.78/.turbo/turbo-build.log +0 -3
  35. classifyre_cli-0.4.78/src/utils/embedded_images.py +0 -222
  36. classifyre_cli-0.4.78/tests/utils/test_embedded_images.py +0 -129
  37. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/.gitignore +0 -0
  38. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/.python-version +0 -0
  39. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/README.md +0 -0
  40. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/main.py +0 -0
  41. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/scripts/generate_models.py +0 -0
  42. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/__init__.py +0 -0
  43. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/config.py +0 -0
  44. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/__init__.py +0 -0
  45. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/base.py +0 -0
  46. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/broken_links/__init__.py +0 -0
  47. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/broken_links/detector.py +0 -0
  48. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/config.py +0 -0
  49. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/content/__init__.py +0 -0
  50. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/custom/__init__.py +0 -0
  51. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/custom/detector.py +0 -0
  52. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/custom/extractor.py +0 -0
  53. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/custom/runners/__init__.py +0 -0
  54. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/custom/runners/_base.py +0 -0
  55. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/custom/runners/_factory.py +0 -0
  56. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/custom/runners/_gliner2.py +0 -0
  57. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/custom/runners/_image_classification.py +0 -0
  58. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/custom/runners/_llm.py +0 -0
  59. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/custom/runners/_object_detection.py +0 -0
  60. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/custom/runners/_regex.py +0 -0
  61. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/custom/runners/_text_classification.py +0 -0
  62. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/custom/trainer.py +0 -0
  63. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/dependencies.py +0 -0
  64. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/engine_version.py +0 -0
  65. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/pii/__init__.py +0 -0
  66. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/pii/detector.py +0 -0
  67. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/secrets/__init__.py +0 -0
  68. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/secrets/detector.py +0 -0
  69. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/threat/__init__.py +0 -0
  70. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/threat/code_security_detector.py +0 -0
  71. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/detectors/threat/yara_detector.py +0 -0
  72. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/file_evaluation/__init__.py +0 -0
  73. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/outputs/__init__.py +0 -0
  74. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/outputs/base.py +0 -0
  75. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/outputs/console.py +0 -0
  76. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/outputs/factory.py +0 -0
  77. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/outputs/file.py +0 -0
  78. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/pipeline/__init__.py +0 -0
  79. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/pipeline/content_provider.py +0 -0
  80. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/pipeline/detector_pipeline.py +0 -0
  81. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/pipeline/text_artifact.py +0 -0
  82. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/pipeline/worker_pool.py +0 -0
  83. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/__init__.py +0 -0
  84. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/asset_metadata.py +0 -0
  85. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/atlassian_common.py +0 -0
  86. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/azure_blob_storage/__init__.py +0 -0
  87. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/azure_blob_storage/source.py +0 -0
  88. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/confluence/__init__.py +0 -0
  89. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/confluence/source.py +0 -0
  90. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/databricks/__init__.py +0 -0
  91. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/databricks/source.py +0 -0
  92. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/delta_lake/__init__.py +0 -0
  93. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/delta_lake/source.py +0 -0
  94. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/dependencies.py +0 -0
  95. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/dropbox/__init__.py +0 -0
  96. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/dropbox/auth.py +0 -0
  97. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/dropbox/source.py +0 -0
  98. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/elasticsearch/__init__.py +0 -0
  99. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/elasticsearch/source.py +0 -0
  100. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/email/__init__.py +0 -0
  101. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/email/source.py +0 -0
  102. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/google_cloud_storage/__init__.py +0 -0
  103. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/google_cloud_storage/source.py +0 -0
  104. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/google_workspace/__init__.py +0 -0
  105. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/google_workspace/source.py +0 -0
  106. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/hive/__init__.py +0 -0
  107. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/hive/source.py +0 -0
  108. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/hugging_face/__init__.py +0 -0
  109. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/hugging_face/source.py +0 -0
  110. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/iceberg/__init__.py +0 -0
  111. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/iceberg/source.py +0 -0
  112. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/jira/__init__.py +0 -0
  113. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/jira/source.py +0 -0
  114. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/kafka/__init__.py +0 -0
  115. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/kafka/rest.py +0 -0
  116. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/kafka/source.py +0 -0
  117. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/lakehouse_base.py +0 -0
  118. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/local_folder/__init__.py +0 -0
  119. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/local_folder/source.py +0 -0
  120. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/meilisearch/__init__.py +0 -0
  121. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/meilisearch/source.py +0 -0
  122. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/microsoft_365/__init__.py +0 -0
  123. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/microsoft_365/source.py +0 -0
  124. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/mongodb/__init__.py +0 -0
  125. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/mongodb/source.py +0 -0
  126. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/mssql/__init__.py +0 -0
  127. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/mssql/source.py +0 -0
  128. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/mysql/__init__.py +0 -0
  129. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/mysql/source.py +0 -0
  130. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/neo4j/__init__.py +0 -0
  131. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/neo4j/source.py +0 -0
  132. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/notion/__init__.py +0 -0
  133. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/notion/client.py +0 -0
  134. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/notion/source.py +0 -0
  135. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/opensearch/__init__.py +0 -0
  136. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/opensearch/source.py +0 -0
  137. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/oracle/__init__.py +0 -0
  138. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/oracle/source.py +0 -0
  139. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/postgresql/__init__.py +0 -0
  140. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/postgresql/source.py +0 -0
  141. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/powerbi/__init__.py +0 -0
  142. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/powerbi/source.py +0 -0
  143. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/recipe_normalizer.py +0 -0
  144. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/s3_client.py +0 -0
  145. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/s3_compatible_storage/README.md +0 -0
  146. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/s3_compatible_storage/__init__.py +0 -0
  147. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/s3_compatible_storage/source.py +0 -0
  148. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/sandbox/__init__.py +0 -0
  149. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/sandbox/source.py +0 -0
  150. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/search_engine_base.py +0 -0
  151. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/servicedesk/__init__.py +0 -0
  152. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/servicedesk/source.py +0 -0
  153. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/slack/__init__.py +0 -0
  154. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/slack/source.py +0 -0
  155. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/snowflake/__init__.py +0 -0
  156. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/snowflake/source.py +0 -0
  157. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/sqlite/__init__.py +0 -0
  158. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/sqlite/source.py +0 -0
  159. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/tableau/__init__.py +0 -0
  160. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/tableau/source.py +0 -0
  161. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/tabular_base.py +0 -0
  162. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/tabular_utils.py +0 -0
  163. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/wordpress/__init__.py +0 -0
  164. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/wordpress/source.py +0 -0
  165. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/sources/youtube/__init__.py +0 -0
  166. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/telemetry.py +0 -0
  167. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/__init__.py +0 -0
  168. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/archive_extraction.py +0 -0
  169. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/content_extraction.py +0 -0
  170. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/file_metadata.py +0 -0
  171. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/file_to_images.py +0 -0
  172. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/hashing.py +0 -0
  173. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/legacy_office.py +0 -0
  174. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/resources.py +0 -0
  175. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/transcription.py +0 -0
  176. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/uv_sync.py +0 -0
  177. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/validation.py +0 -0
  178. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/src/utils/video_processing.py +0 -0
  179. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/__init__.py +0 -0
  180. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/_lakehouse_fakes.py +0 -0
  181. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/conftest.py +0 -0
  182. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/__init__.py +0 -0
  183. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/broken_links/test_broken_links_detector.py +0 -0
  184. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/conftest.py +0 -0
  185. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/content/__init__.py +0 -0
  186. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/custom/__init__.py +0 -0
  187. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/custom/conftest.py +0 -0
  188. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/custom/test_gliner2_classification.py +0 -0
  189. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/custom/test_invoice_extraction.py +0 -0
  190. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/custom/test_llm_runner.py +0 -0
  191. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/custom/test_pipeline_integration.py +0 -0
  192. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/custom/test_regex_runner.py +0 -0
  193. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/custom/test_runner_hardening.py +0 -0
  194. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/custom/test_transformer_runners.py +0 -0
  195. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/pii/__init__.py +0 -0
  196. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/pii/conftest.py +0 -0
  197. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/pii/sample_invoice.pdf +0 -0
  198. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/pii/test_pii_chunking.py +0 -0
  199. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/pii/test_pii_detector.py +0 -0
  200. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/pii/test_pii_detector_extended.py +0 -0
  201. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/pii/test_pii_regional_entities.py +0 -0
  202. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/pii/test_pii_severity.py +0 -0
  203. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/secrets/__init__.py +0 -0
  204. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/secrets/test_secrets_detector.py +0 -0
  205. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/secrets/test_secrets_detector_extended.py +0 -0
  206. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/test_base_detector.py +0 -0
  207. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/test_custom_detector_examples_runtime.py +0 -0
  208. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/test_detector_catalog_commercial.py +0 -0
  209. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/test_detector_pipeline_types.py +0 -0
  210. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/test_detector_schema_examples.py +0 -0
  211. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/test_detector_types.py +0 -0
  212. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/test_phase2_detectors.py +0 -0
  213. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/test_registry.py +0 -0
  214. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/threat/__init__.py +0 -0
  215. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/threat/test_code_security_detector.py +0 -0
  216. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/detectors/threat/test_yara_detector.py +0 -0
  217. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/integration/test_wordpress_broken_links_detector.py +0 -0
  218. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/integration/test_wordpress_links_assets.py +0 -0
  219. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/pipeline/test_detector_outcomes.py +0 -0
  220. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/pipeline/test_worker_pool.py +0 -0
  221. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_assets_metadata_catalog.py +0 -0
  222. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_azure_blob_storage_source.py +0 -0
  223. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_base_source_attachment.py +0 -0
  224. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_base_source_sampling.py +0 -0
  225. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_config.py +0 -0
  226. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_confluence_source.py +0 -0
  227. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_custom_extractor.py +0 -0
  228. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_databricks_source.py +0 -0
  229. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_delta_lake_source.py +0 -0
  230. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_dependency_groups.py +0 -0
  231. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_dropbox_auth_command.py +0 -0
  232. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_dropbox_source.py +0 -0
  233. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_elasticsearch_source.py +0 -0
  234. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_email_source.py +0 -0
  235. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_file_evaluation_runner.py +0 -0
  236. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_google_cloud_storage_source.py +0 -0
  237. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_google_workspace_source.py +0 -0
  238. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_hashing.py +0 -0
  239. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_hive_source.py +0 -0
  240. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_hugging_face_source.py +0 -0
  241. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_iceberg_source.py +0 -0
  242. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_jira_source.py +0 -0
  243. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_kafka_source.py +0 -0
  244. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_local_folder_source.py +0 -0
  245. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_main.py +0 -0
  246. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_meilisearch_source.py +0 -0
  247. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_microsoft_365_source.py +0 -0
  248. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_mongodb_source.py +0 -0
  249. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_mssql_source.py +0 -0
  250. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_mysql_source.py +0 -0
  251. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_neo4j_source.py +0 -0
  252. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_notion_source.py +0 -0
  253. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_opensearch_source.py +0 -0
  254. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_oracle_source.py +0 -0
  255. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_postgresql_source.py +0 -0
  256. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_powerbi_source.py +0 -0
  257. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_recipe_normalizer.py +0 -0
  258. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_sampling_automatic.py +0 -0
  259. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_sandbox_source.py +0 -0
  260. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_servicedesk_source.py +0 -0
  261. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_slack_source.py +0 -0
  262. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_snowflake_source.py +0 -0
  263. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_source_dependency_groups.py +0 -0
  264. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_sqlite_source.py +0 -0
  265. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_tableau_source.py +0 -0
  266. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_tabular_automatic_sampling.py +0 -0
  267. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_tabular_utils.py +0 -0
  268. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_uv_sync.py +0 -0
  269. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_wordpress_source.py +0 -0
  270. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_youtube_source.py +0 -0
  271. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/test_youtube_source_integration.py +0 -0
  272. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/utils/test_archive_extraction.py +0 -0
  273. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/utils/test_content_extraction.py +0 -0
  274. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/utils/test_file_metadata.py +0 -0
  275. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/utils/test_file_parser.py +0 -0
  276. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/utils/test_file_to_images.py +0 -0
  277. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/utils/test_legacy_office.py +0 -0
  278. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/utils/test_transcription.py +0 -0
  279. {classifyre_cli-0.4.78 → classifyre_cli-0.4.80}/tests/utils/test_video_processing.py +0 -0
@@ -0,0 +1,3 @@
1
+ $ uv sync
2
+ Resolved 307 packages in 10ms
3
+ Checked 51 packages in 7ms
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: classifyre-cli
3
- Version: 0.4.78
3
+ Version: 0.4.80
4
4
  Summary: Classifyre CLI — scan and classify unstructured data sources
5
5
  License: MIT
6
6
  Keywords: data,ingestion,metadata,pii,secrets,unstructured
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classifyre/cli",
3
- "version": "0.4.78",
3
+ "version": "0.4.80",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "build": "uv sync",
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "classifyre-cli"
3
- version = "0.4.78"
3
+ version = "0.4.80"
4
4
  description = "Classifyre CLI — scan and classify unstructured data sources"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -246,6 +246,16 @@ youtube = [
246
246
  "yt-dlp>=2025.1.0",
247
247
  "youtube-transcript-api>=1.0.0",
248
248
  ]
249
+ reddit = [
250
+ # Official Reddit API wrapper. Handles OAuth (all three PRAW flows), token
251
+ # refresh and Reddit's own ratelimit headers.
252
+ "praw>=7.8.1,<8.0.0",
253
+ # Reddit posts routinely embed YouTube/Vimeo links; those are analysed with
254
+ # the same yt-dlp + captions + Whisper + frame-OCR pipeline the YouTube
255
+ # source uses (src/utils/external_video.py).
256
+ "yt-dlp>=2025.1.0",
257
+ "youtube-transcript-api>=1.0.0",
258
+ ]
249
259
  delta-lake = [
250
260
  # Pure-Python/Rust Delta reader (delta-rs) — no Spark, no JVM. Table metadata
251
261
  # and data-file lists come from deltalake; rows are sampled through DuckDB
@@ -9,7 +9,7 @@ from pathlib import Path
9
9
  from typing import Any
10
10
 
11
11
  from ..models.generated_single_asset_scan_results import DetectionResult, Location
12
- from ..utils.embedded_images import has_embedded_images, iter_embedded_images
12
+ from ..utils.embedded_files import has_embedded_files, iter_embedded_files
13
13
  from ..utils.file_parser import ParsedFile, parse_file
14
14
 
15
15
  logger = logging.getLogger(__name__)
@@ -148,11 +148,11 @@ class FileEvaluationRunner:
148
148
  file_mime,
149
149
  )
150
150
 
151
- # Files that embed images (parquet image datasets, office docs) get each
152
- # embedded image run through the image/binary detectors directly, with
153
- # findings tagged by the embedded-image location so the UI can group them.
154
- embedded_images = has_embedded_images(mime_type)
155
- if not tasks and not embedded_images:
151
+ # Files that embed whole other files (parquet file columns, office media)
152
+ # get each embedded file run through the binary detectors directly, with
153
+ # findings tagged by the embedded location so the UI can group them.
154
+ embedded_files = has_embedded_files(mime_type)
155
+ if not tasks and not embedded_files:
156
156
  if not text.strip() and not file_mime:
157
157
  logger.warning(
158
158
  "No text content extracted from %s file; skipping text detectors.",
@@ -186,9 +186,9 @@ class FileEvaluationRunner:
186
186
  )
187
187
  )
188
188
 
189
- if embedded_images:
189
+ if embedded_files:
190
190
  all_findings.extend(
191
- await self._run_embedded_image_detectors(
191
+ await self._run_embedded_file_detectors(
192
192
  detectors=detectors,
193
193
  file_bytes=_get_raw_bytes(),
194
194
  mime_type=mime_type,
@@ -198,7 +198,7 @@ class FileEvaluationRunner:
198
198
 
199
199
  return parsed, all_findings
200
200
 
201
- async def _run_embedded_image_detectors(
201
+ async def _run_embedded_file_detectors(
202
202
  self,
203
203
  *,
204
204
  detectors: list[Any],
@@ -206,60 +206,65 @@ class FileEvaluationRunner:
206
206
  mime_type: str,
207
207
  detected_at: datetime,
208
208
  ) -> list[DetectionResult]:
209
- """Run image/binary detectors over each image embedded in a container file.
209
+ """Run binary detectors over each file embedded in a container file.
210
210
 
211
- Sequential by design (one image, one detector at a time) so the job/scan
211
+ Unwindowed on purpose: file evaluation judges one file the user handed over,
212
+ so there is no run-to-run cursor to advance. A scan of the same container
213
+ from a source expands its embedded files into child assets instead, one
214
+ sampling window at a time.
215
+
216
+ Sequential by design (one file, one detector at a time) so the job/scan
212
217
  logs read in order and each detector's outcome is attributable.
213
218
  """
214
219
  binary_detectors = [d for d in detectors if self._is_binary_detector(d)]
215
220
  if not binary_detectors:
216
221
  logger.info(
217
- "File evaluation: %s embeds images but no image-capable detectors are configured; "
218
- "skipping embedded-image scan",
222
+ "File evaluation: %s embeds files but no binary-capable detectors are configured; "
223
+ "skipping embedded-file scan",
219
224
  mime_type,
220
225
  )
221
226
  return []
222
227
 
223
228
  logger.info(
224
- "File evaluation: scanning images embedded in %s with image detectors: [%s]",
229
+ "File evaluation: scanning files embedded in %s with binary detectors: [%s]",
225
230
  mime_type,
226
231
  ", ".join(self._detector_label(d) for d in binary_detectors),
227
232
  )
228
233
 
229
234
  findings: list[DetectionResult] = []
230
- image_count = 0
231
- for image in iter_embedded_images(file_bytes, mime_type):
232
- image_count += 1
233
- size_kb = len(image.image_bytes) / 1024
235
+ embedded_count = 0
236
+ for embedded in iter_embedded_files(file_bytes, mime_type):
237
+ embedded_count += 1
238
+ size_kb = len(embedded.file_bytes) / 1024
234
239
  compatible = [
235
240
  d
236
241
  for d in binary_detectors
237
- if self._supports_mime(d.get_supported_content_types(), image.mime_type)
242
+ if self._supports_mime(d.get_supported_content_types(), embedded.mime_type)
238
243
  ]
239
244
  if not compatible:
240
245
  logger.info(
241
- "File evaluation: embedded image %s (%s, %.0f KB) — no compatible detector",
242
- image.location,
243
- image.mime_type,
246
+ "File evaluation: embedded file %s (%s, %.0f KB) — no compatible detector",
247
+ embedded.location,
248
+ embedded.mime_type,
244
249
  size_kb,
245
250
  )
246
251
  continue
247
252
  logger.info(
248
- "File evaluation: embedded image %s (%s, %.0f KB) → dispatching [%s]",
249
- image.location,
250
- image.mime_type,
253
+ "File evaluation: embedded file %s (%s, %.0f KB) → dispatching [%s]",
254
+ embedded.location,
255
+ embedded.mime_type,
251
256
  size_kb,
252
257
  ", ".join(self._detector_label(d) for d in compatible),
253
258
  )
254
259
  for detector in compatible:
255
260
  label = self._detector_label(detector)
256
261
  try:
257
- result = await detector.detect(image.image_bytes, image.mime_type)
262
+ result = await detector.detect(embedded.file_bytes, embedded.mime_type)
258
263
  except Exception as exc:
259
264
  logger.error(
260
- "File evaluation: '%s' failed on embedded image %s: %s",
265
+ "File evaluation: '%s' failed on embedded file %s: %s",
261
266
  label,
262
- image.location,
267
+ embedded.location,
263
268
  exc,
264
269
  )
265
270
  continue
@@ -269,17 +274,17 @@ class FileEvaluationRunner:
269
274
  else []
270
275
  )
271
276
  logger.info(
272
- "File evaluation: '%s' on embedded image %s → %d finding(s)",
277
+ "File evaluation: '%s' on embedded file %s → %d finding(s)",
273
278
  label,
274
- image.location,
279
+ embedded.location,
275
280
  len(detector_findings),
276
281
  )
277
282
  for finding in detector_findings:
278
- findings.append(self._tag_embedded(finding, image.location, detected_at))
283
+ findings.append(self._tag_embedded(finding, embedded.location, detected_at))
279
284
 
280
285
  logger.info(
281
- "File evaluation: embedded-image scan complete — %d image(s) scanned, %d finding(s)",
282
- image_count,
286
+ "File evaluation: embedded-file scan complete — %d file(s) scanned, %d finding(s)",
287
+ embedded_count,
283
288
  len(findings),
284
289
  )
285
290
  return findings
@@ -299,7 +304,7 @@ class FileEvaluationRunner:
299
304
  def _tag_embedded(
300
305
  finding: DetectionResult, location_label: str, detected_at: datetime
301
306
  ) -> DetectionResult:
302
- """Attach the embedded-image location to a finding for parent-file grouping."""
307
+ """Attach the embedded-file location to a finding for parent-file grouping."""
303
308
  metadata = dict(finding.metadata or {})
304
309
  metadata["embedded_location"] = location_label
305
310
  location = finding.location or Location()
@@ -265,9 +265,22 @@ async def run_command_async(args: argparse.Namespace, recipe: dict[str, Any]) ->
265
265
  worker_pool=worker_pool,
266
266
  )
267
267
 
268
+ from .pipeline.payload_window import PayloadWindowStore
268
269
  from .pipeline.scan_cache import ScanCache
269
270
 
270
- scan_cache = ScanCache(recipe, source)
271
+ # Bounds how much of each asset a run reads, not just how many
272
+ # assets it reads. The scan cache consults it before skipping,
273
+ # so a part-scanned payload is never mistaken for a finished one.
274
+ payload_windows = PayloadWindowStore.from_recipe(recipe)
275
+ if payload_windows.enabled:
276
+ logger.info(
277
+ "Payload sampling active (%s): tabular assets are read %d rows per run",
278
+ payload_windows.strategy,
279
+ payload_windows.rows_per_page,
280
+ )
281
+ source.attach_payload_windows(payload_windows)
282
+
283
+ scan_cache = ScanCache(recipe, source, payload_windows=payload_windows)
271
284
  if scan_cache.enabled:
272
285
  logger.info(
273
286
  "Scan cache active (verify=%s): unchanged assets and"
@@ -292,6 +305,13 @@ async def run_command_async(args: argparse.Namespace, recipe: dict[str, Any]) ->
292
305
  for stub in stub_batch:
293
306
  stub["findings"] = []
294
307
 
308
+ # Teach the payload windows each asset's ids and checksum
309
+ # before any window is built: a stored row offset only
310
+ # resumes when it still matches the file it was measured
311
+ # against.
312
+ for asset in raw_batch:
313
+ payload_windows.bind(asset)
314
+
295
315
  # Register BEFORE ingesting: the API stamps per-run
296
316
  # change_type onto runner_assets rows during ingest, so
297
317
  # the row must exist or the CREATED stamp is lost and
@@ -303,9 +323,15 @@ async def run_command_async(args: argparse.Namespace, recipe: dict[str, Any]) ->
303
323
  # or not at all.
304
324
  hashes = [s["hash"] for s in stub_batch if s.get("hash")]
305
325
  if hasattr(sink, "register_discovered_assets") and hashes:
326
+ want_cursors = payload_windows.persists_cursor
306
327
  prior = await sink.register_discovered_assets(
307
- hashes, include_scan_cache=scan_cache.enabled
328
+ hashes,
329
+ include_scan_cache=scan_cache.enabled,
330
+ include_payload_cursor=want_cursors,
308
331
  )
332
+ if want_cursors and isinstance(prior, tuple):
333
+ prior, payload_cursors = prior
334
+ payload_windows.record_prior(payload_cursors)
309
335
  scan_cache.record_prior(prior)
310
336
 
311
337
  await sink.emit_batch(stub_batch, skip_findings=True)
@@ -477,6 +503,10 @@ async def run_command_async(args: argparse.Namespace, recipe: dict[str, Any]) ->
477
503
  if state is not None:
478
504
  payload["scan_cache"] = state
479
505
 
506
+ cursor = payload_windows.cursor_payload_for(asset)
507
+ if cursor is not None:
508
+ payload["payload_cursor"] = cursor
509
+
480
510
  await sink.emit_batch([payload], skip_findings=False)
481
511
 
482
512
  if hasattr(sink, "update_asset_status"):
@@ -75,6 +75,7 @@ class SourceAssetType(StrEnum):
75
75
  ORACLE = 'ORACLE'
76
76
  HIVE = 'HIVE'
77
77
  POWERBI = 'POWERBI'
78
+ REDDIT = 'REDDIT'
78
79
  SANDBOX = 'SANDBOX'
79
80
 
80
81