warp-server 0.2.3__tar.gz → 0.2.8__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 (229) hide show
  1. {warp_server-0.2.3 → warp_server-0.2.8}/PKG-INFO +51 -1
  2. {warp_server-0.2.3 → warp_server-0.2.8}/README.md +50 -0
  3. {warp_server-0.2.3 → warp_server-0.2.8}/pyproject.toml +1 -1
  4. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/cli.py +68 -1
  5. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/config.py +1 -0
  6. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/main.py +33 -0
  7. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/models.py +21 -0
  8. warp_server-0.2.8/src/warp_server/routers/bndbs.py +215 -0
  9. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/files.py +12 -0
  10. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/schemas.py +22 -0
  11. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/static/index.html +123 -1
  12. {warp_server-0.2.3 → warp_server-0.2.8}/uv.lock +53 -53
  13. {warp_server-0.2.3 → warp_server-0.2.8}/.github/workflows/ci.yml +0 -0
  14. {warp_server-0.2.3 → warp_server-0.2.8}/.gitignore +0 -0
  15. {warp_server-0.2.3 → warp_server-0.2.8}/.gitmodules +0 -0
  16. {warp_server-0.2.3 → warp_server-0.2.8}/.pre-commit-config.yaml +0 -0
  17. {warp_server-0.2.3 → warp_server-0.2.8}/Dockerfile +0 -0
  18. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/__init__.py +0 -0
  19. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/auth.py +0 -0
  20. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/database.py +0 -0
  21. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/BasicBlock.py +0 -0
  22. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/BasicBlockGUID.py +0 -0
  23. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/Constraint.py +0 -0
  24. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/ConstraintGUID.py +0 -0
  25. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/Function.py +0 -0
  26. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/FunctionComment.py +0 -0
  27. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/FunctionGUID.py +0 -0
  28. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/FunctionVariable.py +0 -0
  29. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/SignatureChunk.py +0 -0
  30. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SigBin/__init__.py +0 -0
  31. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SymbolBin/Symbol.py +0 -0
  32. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SymbolBin/SymbolClass.py +0 -0
  33. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SymbolBin/SymbolModifiers.py +0 -0
  34. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/SymbolBin/__init__.py +0 -0
  35. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TargetBin/Target.py +0 -0
  36. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TargetBin/__init__.py +0 -0
  37. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Array.py +0 -0
  38. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/ArrayModifiers.py +0 -0
  39. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/BitOffset.py +0 -0
  40. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/BitShift.py +0 -0
  41. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/BitSize.py +0 -0
  42. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/BitWidth.py +0 -0
  43. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Boolean.py +0 -0
  44. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/CallingConvention.py +0 -0
  45. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Character.py +0 -0
  46. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/ComputedType.py +0 -0
  47. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Enumeration.py +0 -0
  48. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/EnumerationMember.py +0 -0
  49. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Float.py +0 -0
  50. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Function.py +0 -0
  51. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/FunctionMember.py +0 -0
  52. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Integer.py +0 -0
  53. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/LocationClass.py +0 -0
  54. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/MetadataValueType.py +0 -0
  55. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Pointer.py +0 -0
  56. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/PointerAddressing.py +0 -0
  57. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Referrer.py +0 -0
  58. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/RegisterLocation.py +0 -0
  59. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/StackLocation.py +0 -0
  60. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Structure.py +0 -0
  61. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/StructureMember.py +0 -0
  62. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/StructureMemberModifiers.py +0 -0
  63. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Type.py +0 -0
  64. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/TypeChunk.py +0 -0
  65. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/TypeClass.py +0 -0
  66. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/TypeGUID.py +0 -0
  67. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/TypeMetadata.py +0 -0
  68. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/TypeModifiers.py +0 -0
  69. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Union.py +0 -0
  70. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/UnionMember.py +0 -0
  71. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/UnsignedBitOffset.py +0 -0
  72. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/Void.py +0 -0
  73. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/TypeBin/__init__.py +0 -0
  74. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/Chunk.py +0 -0
  75. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/ChunkHeader.py +0 -0
  76. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/ChunkType.py +0 -0
  77. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/CompressionType.py +0 -0
  78. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/File.py +0 -0
  79. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/FileHeader.py +0 -0
  80. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/Warp/__init__.py +0 -0
  81. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/gen_flatbuffers/__init__.py +0 -0
  82. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/__init__.py +0 -0
  83. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/auth.py +0 -0
  84. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/commits.py +0 -0
  85. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/functions.py +0 -0
  86. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/search.py +0 -0
  87. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/sources.py +0 -0
  88. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/status.py +0 -0
  89. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/symbols.py +0 -0
  90. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/targets.py +0 -0
  91. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/types.py +0 -0
  92. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/routers/users.py +0 -0
  93. {warp_server-0.2.3 → warp_server-0.2.8}/src/warp_server/warp_parser.py +0 -0
  94. {warp_server-0.2.3 → warp_server-0.2.8}/tests/__init__.py +0 -0
  95. {warp_server-0.2.3 → warp_server-0.2.8}/tests/conftest.py +0 -0
  96. {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_commits.py +0 -0
  97. {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_files.py +0 -0
  98. {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_functions.py +0 -0
  99. {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_ingest.py +0 -0
  100. {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_lockout.py +0 -0
  101. {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_search.py +0 -0
  102. {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_sources.py +0 -0
  103. {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_status.py +0 -0
  104. {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_targets.py +0 -0
  105. {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_users.py +0 -0
  106. {warp_server-0.2.3 → warp_server-0.2.8}/tests/test_warp_parser.py +0 -0
  107. {warp_server-0.2.3 → warp_server-0.2.8}/warp/.git +0 -0
  108. {warp_server-0.2.3 → warp_server-0.2.8}/warp/.github/workflows/CI.yaml +0 -0
  109. {warp_server-0.2.3 → warp_server-0.2.8}/warp/.gitignore +0 -0
  110. {warp_server-0.2.3 → warp_server-0.2.8}/warp/Cargo.toml +0 -0
  111. {warp_server-0.2.3 → warp_server-0.2.8}/warp/LICENSE +0 -0
  112. {warp_server-0.2.3 → warp_server-0.2.8}/warp/README.md +0 -0
  113. {warp_server-0.2.3 → warp_server-0.2.8}/warp/about.hbs +0 -0
  114. {warp_server-0.2.3 → warp_server-0.2.8}/warp/about.toml +0 -0
  115. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/Cargo.toml +0 -0
  116. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/benches/chunk.rs +0 -0
  117. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/benches/type.rs +0 -0
  118. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/build.rs +0 -0
  119. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/examples/dumper.rs +0 -0
  120. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/examples/random.rs +0 -0
  121. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/examples/type_builder.rs +0 -0
  122. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/fixtures/random.warp +0 -0
  123. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/fuzz/.gitignore +0 -0
  124. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/fuzz/Cargo.toml +0 -0
  125. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/fuzz/fuzz_targets/file.rs +0 -0
  126. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/fuzz/fuzz_targets/function.rs +0 -0
  127. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/fuzz/fuzz_targets/type.rs +0 -0
  128. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/cached_builder.rs +0 -0
  129. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/chunk.rs +0 -0
  130. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/mod.rs +0 -0
  131. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/basic_block_generated.rs +0 -0
  132. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/basic_block_guid_generated.rs +0 -0
  133. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/constraint_generated.rs +0 -0
  134. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/constraint_guid_generated.rs +0 -0
  135. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/function_comment_generated.rs +0 -0
  136. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/function_generated.rs +0 -0
  137. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/function_guid_generated.rs +0 -0
  138. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/function_variable_generated.rs +0 -0
  139. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/sig_bin/signature_chunk_generated.rs +0 -0
  140. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/symbol_bin/symbol_class_generated.rs +0 -0
  141. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/symbol_bin/symbol_generated.rs +0 -0
  142. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/symbol_bin/symbol_modifiers_generated.rs +0 -0
  143. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/target_bin/target_generated.rs +0 -0
  144. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/array_generated.rs +0 -0
  145. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/array_modifiers_generated.rs +0 -0
  146. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/bit_offset_generated.rs +0 -0
  147. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/bit_shift_generated.rs +0 -0
  148. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/bit_size_generated.rs +0 -0
  149. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/bit_width_generated.rs +0 -0
  150. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/boolean_generated.rs +0 -0
  151. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/calling_convention_generated.rs +0 -0
  152. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/character_generated.rs +0 -0
  153. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/computed_type_generated.rs +0 -0
  154. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/enumeration_generated.rs +0 -0
  155. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/enumeration_member_generated.rs +0 -0
  156. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/float_generated.rs +0 -0
  157. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/function_generated.rs +0 -0
  158. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/function_member_generated.rs +0 -0
  159. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/function_member_location_generated.rs +0 -0
  160. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/integer_generated.rs +0 -0
  161. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/location_class_generated.rs +0 -0
  162. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/metadata_value_type_generated.rs +0 -0
  163. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/pointer_addressing_generated.rs +0 -0
  164. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/pointer_generated.rs +0 -0
  165. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/referrer_generated.rs +0 -0
  166. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/register_location_generated.rs +0 -0
  167. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/stack_location_generated.rs +0 -0
  168. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/structure_generated.rs +0 -0
  169. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/structure_member_generated.rs +0 -0
  170. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/structure_member_modifiers_generated.rs +0 -0
  171. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/type_chunk_generated.rs +0 -0
  172. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/type_class_generated.rs +0 -0
  173. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/type_generated.rs +0 -0
  174. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/type_guid_generated.rs +0 -0
  175. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/type_metadata_generated.rs +0 -0
  176. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/type_modifiers_generated.rs +0 -0
  177. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/union_generated.rs +0 -0
  178. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/union_member_generated.rs +0 -0
  179. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/unsigned_bit_offset_generated.rs +0 -0
  180. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/type_bin/void_generated.rs +0 -0
  181. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/warp/chunk_generated.rs +0 -0
  182. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/warp/chunk_header_generated.rs +0 -0
  183. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/warp/chunk_type_generated.rs +0 -0
  184. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/warp/compression_type_generated.rs +0 -0
  185. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/warp/file_generated.rs +0 -0
  186. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/gen_flatbuffers/warp/file_header_generated.rs +0 -0
  187. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/lib.rs +0 -0
  188. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/mock.rs +0 -0
  189. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature/basic_block.rs +0 -0
  190. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature/chunk.rs +0 -0
  191. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature/comment.rs +0 -0
  192. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature/constraint.rs +0 -0
  193. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature/function.rs +0 -0
  194. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature/variable.rs +0 -0
  195. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/signature.rs +0 -0
  196. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/symbol.rs +0 -0
  197. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/target.rs +0 -0
  198. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/chunk.rs +0 -0
  199. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/array.rs +0 -0
  200. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/boolean.rs +0 -0
  201. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/character.rs +0 -0
  202. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/enumeration.rs +0 -0
  203. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/float.rs +0 -0
  204. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/function.rs +0 -0
  205. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/integer.rs +0 -0
  206. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/pointer.rs +0 -0
  207. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/referrer.rs +0 -0
  208. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/structure.rs +0 -0
  209. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/union.rs +0 -0
  210. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class/void.rs +0 -0
  211. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/class.rs +0 -0
  212. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type/guid.rs +0 -0
  213. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/src/type.rs +0 -0
  214. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/tests/chunk.rs +0 -0
  215. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/tests/file.rs +0 -0
  216. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/tests/signature.rs +0 -0
  217. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/tests/snapshots/file__file_format_regression.snap +0 -0
  218. {warp_server-0.2.3 → warp_server-0.2.8}/warp/rust/tests/types.rs +0 -0
  219. {warp_server-0.2.3 → warp_server-0.2.8}/warp/signature.fbs +0 -0
  220. {warp_server-0.2.3 → warp_server-0.2.8}/warp/symbol.fbs +0 -0
  221. {warp_server-0.2.3 → warp_server-0.2.8}/warp/target.fbs +0 -0
  222. {warp_server-0.2.3 → warp_server-0.2.8}/warp/type.fbs +0 -0
  223. {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp.fbs +0 -0
  224. {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp_cli/Cargo.toml +0 -0
  225. {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp_cli/src/main.rs +0 -0
  226. {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp_cli/src/operation/find.rs +0 -0
  227. {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp_cli/src/operation/merge.rs +0 -0
  228. {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp_cli/src/operation.rs +0 -0
  229. {warp_server-0.2.3 → warp_server-0.2.8}/warp/warp_cli/src/utility.rs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: warp-server
3
- Version: 0.2.3
3
+ Version: 0.2.8
4
4
  Summary: WARP signature server API
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: aiosqlite>=0.20
@@ -144,6 +144,54 @@ Log in with your username and API key. The UI lets you:
144
144
  - Manage users (admin only)
145
145
  - Create API keys
146
146
  - Browse functions and commits
147
+ - Upload, browse, and download BNDBs
148
+
149
+ ## BNDB Sharing
150
+
151
+ The server supports uploading and downloading Binary Ninja Database (`.bndb`) files.
152
+ Files are stored on disk as gzip-compressed blobs in a configurable directory, keeping
153
+ the SQLite metadata database lightweight.
154
+
155
+ Any authenticated user can upload or download BNDBs. Only the uploader (or an admin)
156
+ can delete them.
157
+
158
+ ### API
159
+
160
+ ```bash
161
+ # upload a BNDB
162
+ curl -X POST http://localhost:8000/api/v1/bndbs \
163
+ -H "Authorization: Bearer <key>" \
164
+ -F "file=@firmware.bndb" \
165
+ -F "name=firmware.bndb" \
166
+ -F "description=Extracted from router firmware"
167
+
168
+ # list / search BNDBs
169
+ curl -X POST http://localhost:8000/api/v1/bndbs/query \
170
+ -H "Authorization: Bearer <key>" \
171
+ -H "Content-Type: application/json" \
172
+ -d '{"name": "firmware", "limit": 20, "page": 1}'
173
+
174
+ # get metadata
175
+ curl -H "Authorization: Bearer <key>" \
176
+ http://localhost:8000/api/v1/bndbs/<uuid>
177
+
178
+ # download
179
+ curl -H "Authorization: Bearer <key>" -o output.bndb \
180
+ http://localhost:8000/api/v1/bndbs/<uuid>/download
181
+
182
+ # delete (owner or admin)
183
+ curl -X DELETE -H "Authorization: Bearer <key>" \
184
+ http://localhost:8000/api/v1/bndbs/<uuid>
185
+ ```
186
+
187
+ BNDBs can also be managed from the **BNDBs** tab in the web UI.
188
+
189
+ ### Storage
190
+
191
+ BNDB files are stored as `<uuid>.bndb.gz` in the directory configured by
192
+ `WARP_BNDB_STORAGE_DIR` (default `./bndb_storage`). The directory is created
193
+ automatically on server startup. Compression is transparent — clients always
194
+ upload and download raw `.bndb` files.
147
195
 
148
196
  ## Configuration
149
197
 
@@ -157,6 +205,7 @@ The server is configured via environment variables, all prefixed with `WARP_`.
157
205
  | `WARP_PORT` | `8000` | Listen port. |
158
206
  | `WARP_LOG_LEVEL` | `info` | Uvicorn log level (`debug`, `info`, `warning`, `error`). |
159
207
  | `WARP_RELOAD` | `false` | Enable auto-reload on file changes (dev only). |
208
+ | `WARP_BNDB_STORAGE_DIR` | `./bndb_storage` | Directory for uploaded BNDB files (created automatically). |
160
209
  | `WARP_CORS_ORIGINS` | `[]` | JSON list of allowed CORS origins, e.g. `'["https://app.example.com"]'`. |
161
210
  | `WARP_TRUSTED_PROXIES` | `[]` | JSON list of trusted reverse-proxy IPs allowed to set `X-Forwarded-For`. |
162
211
  | `WARP_MAX_LOGIN_ATTEMPTS` | `5` | Failed attempts before an IP or user account is locked. |
@@ -202,3 +251,4 @@ Migrations are idempotent and safe to re-run. Current migrations:
202
251
 
203
252
  - **hash-keys** — hashes any plaintext API keys (SHA-256). After migration, previously issued raw keys become invalid; create new ones via `warp-ctl key create` or the web UI.
204
253
  - **lockout-columns** — adds `locked`, `failed_login_count`, and `locked_at` columns to the `users` table for account lockout support.
254
+ - **purge-auto-names** — deletes functions and symbols with auto-generated names (`sub_`, `nullsub`, `j_sub_`, `outlined_sub_`, `_OUTLINED_FUNCTION`).
@@ -128,6 +128,54 @@ Log in with your username and API key. The UI lets you:
128
128
  - Manage users (admin only)
129
129
  - Create API keys
130
130
  - Browse functions and commits
131
+ - Upload, browse, and download BNDBs
132
+
133
+ ## BNDB Sharing
134
+
135
+ The server supports uploading and downloading Binary Ninja Database (`.bndb`) files.
136
+ Files are stored on disk as gzip-compressed blobs in a configurable directory, keeping
137
+ the SQLite metadata database lightweight.
138
+
139
+ Any authenticated user can upload or download BNDBs. Only the uploader (or an admin)
140
+ can delete them.
141
+
142
+ ### API
143
+
144
+ ```bash
145
+ # upload a BNDB
146
+ curl -X POST http://localhost:8000/api/v1/bndbs \
147
+ -H "Authorization: Bearer <key>" \
148
+ -F "file=@firmware.bndb" \
149
+ -F "name=firmware.bndb" \
150
+ -F "description=Extracted from router firmware"
151
+
152
+ # list / search BNDBs
153
+ curl -X POST http://localhost:8000/api/v1/bndbs/query \
154
+ -H "Authorization: Bearer <key>" \
155
+ -H "Content-Type: application/json" \
156
+ -d '{"name": "firmware", "limit": 20, "page": 1}'
157
+
158
+ # get metadata
159
+ curl -H "Authorization: Bearer <key>" \
160
+ http://localhost:8000/api/v1/bndbs/<uuid>
161
+
162
+ # download
163
+ curl -H "Authorization: Bearer <key>" -o output.bndb \
164
+ http://localhost:8000/api/v1/bndbs/<uuid>/download
165
+
166
+ # delete (owner or admin)
167
+ curl -X DELETE -H "Authorization: Bearer <key>" \
168
+ http://localhost:8000/api/v1/bndbs/<uuid>
169
+ ```
170
+
171
+ BNDBs can also be managed from the **BNDBs** tab in the web UI.
172
+
173
+ ### Storage
174
+
175
+ BNDB files are stored as `<uuid>.bndb.gz` in the directory configured by
176
+ `WARP_BNDB_STORAGE_DIR` (default `./bndb_storage`). The directory is created
177
+ automatically on server startup. Compression is transparent — clients always
178
+ upload and download raw `.bndb` files.
131
179
 
132
180
  ## Configuration
133
181
 
@@ -141,6 +189,7 @@ The server is configured via environment variables, all prefixed with `WARP_`.
141
189
  | `WARP_PORT` | `8000` | Listen port. |
142
190
  | `WARP_LOG_LEVEL` | `info` | Uvicorn log level (`debug`, `info`, `warning`, `error`). |
143
191
  | `WARP_RELOAD` | `false` | Enable auto-reload on file changes (dev only). |
192
+ | `WARP_BNDB_STORAGE_DIR` | `./bndb_storage` | Directory for uploaded BNDB files (created automatically). |
144
193
  | `WARP_CORS_ORIGINS` | `[]` | JSON list of allowed CORS origins, e.g. `'["https://app.example.com"]'`. |
145
194
  | `WARP_TRUSTED_PROXIES` | `[]` | JSON list of trusted reverse-proxy IPs allowed to set `X-Forwarded-For`. |
146
195
  | `WARP_MAX_LOGIN_ATTEMPTS` | `5` | Failed attempts before an IP or user account is locked. |
@@ -186,3 +235,4 @@ Migrations are idempotent and safe to re-run. Current migrations:
186
235
 
187
236
  - **hash-keys** — hashes any plaintext API keys (SHA-256). After migration, previously issued raw keys become invalid; create new ones via `warp-ctl key create` or the web UI.
188
237
  - **lockout-columns** — adds `locked`, `failed_login_count`, and `locked_at` columns to the `users` table for account lockout support.
238
+ - **purge-auto-names** — deletes functions and symbols with auto-generated names (`sub_`, `nullsub`, `j_sub_`, `outlined_sub_`, `_OUTLINED_FUNCTION`).
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "warp-server"
3
- version = "0.2.3"
3
+ version = "0.2.8"
4
4
  description = "WARP signature server API"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -7,7 +7,7 @@ from datetime import datetime, timezone
7
7
  from pathlib import Path
8
8
 
9
9
  import click
10
- from sqlalchemy import inspect, select, text, update
10
+ from sqlalchemy import delete, inspect, select, text, update
11
11
 
12
12
  from warp_server.auth import hash_api_key
13
13
  from warp_server.database import async_session, engine
@@ -15,10 +15,14 @@ from warp_server.models import (
15
15
  ApiKey,
16
16
  Base,
17
17
  Commit,
18
+ Function,
19
+ FunctionComment,
20
+ FunctionConstraint,
18
21
  LoginAttempt,
19
22
  Source,
20
23
  SourceTag,
21
24
  SourceUser,
25
+ Symbol,
22
26
  User,
23
27
  )
24
28
 
@@ -604,6 +608,66 @@ async def _migration_lockout_columns(conn, db, apply: bool) -> bool:
604
608
  return True
605
609
 
606
610
 
611
+ _IGNORED_NAME_PREFIXES = (
612
+ "sub_",
613
+ "nullsub",
614
+ "j_sub_",
615
+ "outlined_sub_",
616
+ "_OUTLINED_FUNCTION",
617
+ )
618
+
619
+
620
+ async def _migration_purge_auto_names(db, apply: bool) -> bool:
621
+ """Delete functions/symbols with auto-generated names (sub_, nullsub, etc.)."""
622
+ sym_sub = (
623
+ select(Symbol.id)
624
+ .where(
625
+ Symbol.name.like("sub_%")
626
+ | Symbol.name.like("nullsub%")
627
+ | Symbol.name.like("j_sub_%")
628
+ | Symbol.name.like("outlined_sub_%")
629
+ | Symbol.name.like("_OUTLINED_FUNCTION%")
630
+ )
631
+ .scalar_subquery()
632
+ )
633
+
634
+ func_sub = (
635
+ select(Function.id).where(Function.symbol_id.in_(sym_sub)).scalar_subquery()
636
+ )
637
+
638
+ result = await db.execute(
639
+ select(
640
+ select(Symbol.id).where(Symbol.id.in_(sym_sub)).count(),
641
+ select(Function.id).where(Function.id.in_(func_sub)).count(),
642
+ )
643
+ )
644
+ n_symbols, n_functions = result.one()
645
+
646
+ if n_symbols == 0:
647
+ return False
648
+
649
+ click.echo(
650
+ f" purge-auto-names: {n_symbols} symbol(s), {n_functions} function(s) to purge"
651
+ )
652
+ if apply:
653
+ await db.execute(
654
+ delete(FunctionComment).where(FunctionComment.function_id.in_(func_sub))
655
+ )
656
+ await db.execute(
657
+ delete(FunctionConstraint).where(
658
+ FunctionConstraint.function_id.in_(func_sub)
659
+ )
660
+ )
661
+ await db.execute(delete(Function).where(Function.symbol_id.in_(sym_sub)))
662
+ await db.execute(delete(Symbol).where(Symbol.id.in_(sym_sub)))
663
+ await db.commit()
664
+ click.echo(
665
+ f" purge-auto-names: purged {n_functions} function(s) "
666
+ f"and {n_symbols} symbol(s)"
667
+ )
668
+ return True
669
+
670
+
607
671
  @app.command("migrate")
608
672
  @click.option(
609
673
  "--apply", is_flag=True, help="Actually write changes (default is dry-run)."
@@ -629,6 +693,9 @@ def migrate(apply):
629
693
  if await _migration_lockout_columns(conn, db, apply):
630
694
  pending += 1
631
695
 
696
+ if await _migration_purge_auto_names(db, apply):
697
+ pending += 1
698
+
632
699
  if pending == 0:
633
700
  click.echo("Everything up to date — no migrations needed.")
634
701
  elif not apply:
@@ -11,6 +11,7 @@ class Settings(BaseSettings):
11
11
  lockout_duration_minutes: int = 30
12
12
  reload: bool = False
13
13
  debug: bool = False
14
+ bndb_storage_dir: str = "./bndb_storage"
14
15
  # IPs of trusted reverse proxies allowed to set X-Forwarded-For
15
16
  trusted_proxies: list[str] = []
16
17
 
@@ -1,3 +1,4 @@
1
+ import gzip
1
2
  import logging
2
3
  import time
3
4
  from contextlib import asynccontextmanager
@@ -14,6 +15,7 @@ from warp_server.database import engine
14
15
  from warp_server.models import Base
15
16
  from warp_server.routers import (
16
17
  auth,
18
+ bndbs,
17
19
  commits,
18
20
  files,
19
21
  functions,
@@ -33,6 +35,7 @@ logger = logging.getLogger("warp_server")
33
35
  async def lifespan(app: FastAPI):
34
36
  async with engine.begin() as conn:
35
37
  await conn.run_sync(Base.metadata.create_all)
38
+ Path(settings.bndb_storage_dir).mkdir(parents=True, exist_ok=True)
36
39
  yield
37
40
  await engine.dispose()
38
41
 
@@ -47,6 +50,35 @@ app = FastAPI(
47
50
  )
48
51
 
49
52
 
53
+ @app.middleware("http")
54
+ async def decompress_gzip_request(request: Request, call_next):
55
+ if request.headers.get("content-encoding") == "gzip":
56
+ body = await request.body()
57
+ try:
58
+ decompressed = gzip.decompress(body)
59
+ except Exception:
60
+ pass
61
+ else:
62
+ scope = request.scope
63
+
64
+ # Replace body with decompressed data
65
+ async def receive():
66
+ return {
67
+ "type": "http.request",
68
+ "body": decompressed,
69
+ "more_body": False,
70
+ }
71
+
72
+ request = Request(scope, receive)
73
+ # Remove content-encoding so downstream doesn't re-process
74
+ if "content-encoding" in request.headers.keys():
75
+ raw_headers = [
76
+ (k, v) for k, v in scope["headers"] if k != b"content-encoding"
77
+ ]
78
+ scope["headers"] = raw_headers
79
+ return await call_next(request)
80
+
81
+
50
82
  @app.middleware("http")
51
83
  async def log_request_duration(request: Request, call_next):
52
84
  start = time.perf_counter()
@@ -73,6 +105,7 @@ app.include_router(functions.router)
73
105
  app.include_router(files.router)
74
106
  app.include_router(types.router)
75
107
  app.include_router(search.router)
108
+ app.include_router(bndbs.router)
76
109
 
77
110
  # -- Static web UI ---------------------------------------------------------
78
111
  _static_dir = Path(__file__).parent / "static"
@@ -252,3 +252,24 @@ class Type(Base):
252
252
  created_at = Column(
253
253
  DateTime, default=lambda: datetime.now(timezone.utc), nullable=False
254
254
  )
255
+
256
+
257
+ # ── BNDBs ────────────────────────────────────────────────────────────
258
+
259
+
260
+ class Bndb(Base):
261
+ __tablename__ = "bndbs"
262
+
263
+ id = Column(Integer, primary_key=True, autoincrement=True)
264
+ uuid = Column(Uuid, unique=True, nullable=False, default=uuid.uuid4)
265
+ name = Column(String, nullable=False)
266
+ description = Column(Text, nullable=True)
267
+ user_id = Column(
268
+ Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True
269
+ )
270
+ size_original = Column(Integer, nullable=False)
271
+ size_compressed = Column(Integer, nullable=False)
272
+ sha256 = Column(String(64), nullable=False)
273
+ created_at = Column(
274
+ DateTime, default=lambda: datetime.now(timezone.utc), nullable=False
275
+ )
@@ -0,0 +1,215 @@
1
+ import asyncio
2
+ import gzip
3
+ import hashlib
4
+ import logging
5
+ import math
6
+ from pathlib import Path
7
+ from uuid import UUID, uuid4
8
+
9
+ from fastapi import APIRouter, Depends, Form, HTTPException, UploadFile, status
10
+ from fastapi.responses import StreamingResponse
11
+ from sqlalchemy import func, select
12
+ from sqlalchemy.ext.asyncio import AsyncSession
13
+
14
+ from warp_server.auth import get_current_user
15
+ from warp_server.config import settings
16
+ from warp_server.database import get_db
17
+ from warp_server.models import Bndb, User
18
+ from warp_server.schemas import BndbMdl, BndbQueryRequest, PaginatedResponse
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ router = APIRouter(prefix="/api/v1/bndbs", tags=["bndbs"])
23
+
24
+ CHUNK_SIZE = 256 * 1024 # 256 KB
25
+
26
+
27
+ def _storage_dir() -> Path:
28
+ return Path(settings.bndb_storage_dir)
29
+
30
+
31
+ def _bndb_path(bndb_uuid: UUID) -> Path:
32
+ return _storage_dir() / f"{bndb_uuid}.bndb.gz"
33
+
34
+
35
+ def _bndb_to_response(bndb: Bndb, username: str | None = None) -> BndbMdl:
36
+ return BndbMdl(
37
+ id=bndb.id,
38
+ uuid=bndb.uuid,
39
+ name=bndb.name,
40
+ description=bndb.description,
41
+ user_id=bndb.user_id,
42
+ username=username,
43
+ size_original=bndb.size_original,
44
+ size_compressed=bndb.size_compressed,
45
+ sha256=bndb.sha256,
46
+ created_at=bndb.created_at,
47
+ )
48
+
49
+
50
+ async def _stream_compress_upload(
51
+ upload: UploadFile, dest: Path
52
+ ) -> tuple[int, int, str]:
53
+ """Stream an upload through gzip to disk.
54
+
55
+ Returns (original_size, compressed_size, sha256_hex).
56
+ """
57
+ sha = hashlib.sha256()
58
+ original_size = 0
59
+
60
+ def _write_sync():
61
+ nonlocal original_size
62
+ with gzip.open(dest, "wb", compresslevel=6) as gz:
63
+ while True:
64
+ chunk = upload.file.read(CHUNK_SIZE)
65
+ if not chunk:
66
+ break
67
+ sha.update(chunk)
68
+ original_size += len(chunk)
69
+ gz.write(chunk)
70
+
71
+ await asyncio.to_thread(_write_sync)
72
+
73
+ compressed_size = dest.stat().st_size
74
+ return original_size, compressed_size, sha.hexdigest()
75
+
76
+
77
+ @router.post("", response_model=BndbMdl)
78
+ async def upload_bndb(
79
+ file: UploadFile,
80
+ name: str = Form(...),
81
+ description: str | None = Form(None),
82
+ db: AsyncSession = Depends(get_db),
83
+ user: User = Depends(get_current_user),
84
+ ):
85
+ bndb = Bndb(
86
+ uuid=uuid4(),
87
+ name=name,
88
+ description=description,
89
+ user_id=user.id,
90
+ size_original=0,
91
+ size_compressed=0,
92
+ sha256="",
93
+ )
94
+ dest = _bndb_path(bndb.uuid)
95
+
96
+ try:
97
+ original, compressed, sha256_hex = await _stream_compress_upload(file, dest)
98
+ bndb.size_original = original
99
+ bndb.size_compressed = compressed
100
+ bndb.sha256 = sha256_hex
101
+
102
+ db.add(bndb)
103
+ await db.commit()
104
+ await db.refresh(bndb)
105
+ except Exception:
106
+ dest.unlink(missing_ok=True)
107
+ raise
108
+
109
+ logger.info(
110
+ "BNDB upload %s: %d → %d bytes (%.0f%% compression)",
111
+ name,
112
+ original,
113
+ compressed,
114
+ (1 - compressed / original) * 100 if original else 0,
115
+ )
116
+
117
+ return _bndb_to_response(bndb, user.username)
118
+
119
+
120
+ @router.post("/query", response_model=PaginatedResponse[BndbMdl])
121
+ async def query_bndbs(
122
+ body: BndbQueryRequest,
123
+ db: AsyncSession = Depends(get_db),
124
+ _user: User = Depends(get_current_user),
125
+ ):
126
+ limit = body.limit or 50
127
+ page = body.page or 1
128
+
129
+ query = select(Bndb, User.username).outerjoin(User, Bndb.user_id == User.id)
130
+ count_query = select(func.count(Bndb.id))
131
+
132
+ if body.name:
133
+ query = query.where(Bndb.name.ilike(f"%{body.name}%"))
134
+ count_query = count_query.where(Bndb.name.ilike(f"%{body.name}%"))
135
+
136
+ total = (await db.execute(count_query)).scalar() or 0
137
+ total_pages = max(1, math.ceil(total / limit))
138
+
139
+ query = query.order_by(Bndb.created_at.desc())
140
+ query = query.offset((page - 1) * limit).limit(limit)
141
+
142
+ result = await db.execute(query)
143
+ items = [_bndb_to_response(row.Bndb, row.username) for row in result.all()]
144
+
145
+ return PaginatedResponse(items=items, total_pages=total_pages, total_results=total)
146
+
147
+
148
+ @router.get("/{bndb_uuid}", response_model=BndbMdl)
149
+ async def get_bndb(
150
+ bndb_uuid: UUID,
151
+ db: AsyncSession = Depends(get_db),
152
+ _user: User = Depends(get_current_user),
153
+ ):
154
+ result = await db.execute(
155
+ select(Bndb, User.username)
156
+ .outerjoin(User, Bndb.user_id == User.id)
157
+ .where(Bndb.uuid == bndb_uuid)
158
+ )
159
+ row = result.one_or_none()
160
+ if row is None:
161
+ raise HTTPException(status_code=404, detail="BNDB not found")
162
+ return _bndb_to_response(row.Bndb, row.username)
163
+
164
+
165
+ @router.get("/{bndb_uuid}/download")
166
+ async def download_bndb(
167
+ bndb_uuid: UUID,
168
+ db: AsyncSession = Depends(get_db),
169
+ _user: User = Depends(get_current_user),
170
+ ):
171
+ result = await db.execute(select(Bndb).where(Bndb.uuid == bndb_uuid))
172
+ bndb = result.scalar_one_or_none()
173
+ if bndb is None:
174
+ raise HTTPException(status_code=404, detail="BNDB not found")
175
+
176
+ path = _bndb_path(bndb.uuid)
177
+ if not path.exists():
178
+ raise HTTPException(status_code=404, detail="BNDB file missing from storage")
179
+
180
+ def _decompress_stream():
181
+ with gzip.open(path, "rb") as gz:
182
+ while chunk := gz.read(CHUNK_SIZE):
183
+ yield chunk
184
+
185
+ filename = bndb.name if bndb.name.endswith(".bndb") else bndb.name + ".bndb"
186
+ safe_name = filename.replace('"', "'")
187
+ return StreamingResponse(
188
+ _decompress_stream(),
189
+ media_type="application/octet-stream",
190
+ headers={
191
+ "Content-Disposition": f'attachment; filename="{safe_name}"',
192
+ "Content-Length": str(bndb.size_original),
193
+ },
194
+ )
195
+
196
+
197
+ @router.delete("/{bndb_uuid}", status_code=status.HTTP_204_NO_CONTENT)
198
+ async def delete_bndb(
199
+ bndb_uuid: UUID,
200
+ db: AsyncSession = Depends(get_db),
201
+ user: User = Depends(get_current_user),
202
+ ):
203
+ result = await db.execute(select(Bndb).where(Bndb.uuid == bndb_uuid))
204
+ bndb = result.scalar_one_or_none()
205
+ if bndb is None:
206
+ raise HTTPException(status_code=404, detail="BNDB not found")
207
+
208
+ if bndb.user_id != user.id and user.role != "Admin":
209
+ raise HTTPException(status_code=403, detail="Only the owner or an admin can delete this BNDB")
210
+
211
+ path = _bndb_path(bndb.uuid)
212
+ await db.delete(bndb)
213
+ await db.commit()
214
+
215
+ path.unlink(missing_ok=True)
@@ -158,6 +158,14 @@ async def push_file_json(
158
158
 
159
159
  BATCH_SIZE = 500
160
160
 
161
+ _IGNORED_NAME_PREFIXES = (
162
+ "sub_",
163
+ "nullsub",
164
+ "j_sub_",
165
+ "outlined_sub_",
166
+ "_OUTLINED_FUNCTION",
167
+ )
168
+
161
169
 
162
170
  async def _get_or_create_target(
163
171
  db: AsyncSession,
@@ -191,6 +199,8 @@ async def _resolve_symbols(
191
199
  needed: set[tuple[str, str, str]] = set()
192
200
  for chunk in chunks:
193
201
  for pf in chunk.functions:
202
+ if pf.symbol.name.startswith(_IGNORED_NAME_PREFIXES):
203
+ continue
194
204
  needed.add((pf.symbol.name, pf.symbol.symbol_class, pf.symbol.modifier))
195
205
 
196
206
  if not needed:
@@ -291,6 +301,8 @@ async def _ingest_chunks(
291
301
  )
292
302
 
293
303
  for pf in chunk.functions:
304
+ if pf.symbol.name.startswith(_IGNORED_NAME_PREFIXES):
305
+ continue
294
306
  sym_key = (pf.symbol.name, pf.symbol.symbol_class, pf.symbol.modifier)
295
307
  func_rows.append(
296
308
  {
@@ -291,3 +291,25 @@ class SearchResponse(BaseModel):
291
291
  limit: int
292
292
  offset: int
293
293
  items: list[SearchIndexRow]
294
+
295
+
296
+ # ── BNDBs ────────────────────────────────────────────────────────────
297
+
298
+
299
+ class BndbMdl(BaseModel):
300
+ id: int
301
+ uuid: UUID
302
+ name: str
303
+ description: str | None = None
304
+ user_id: int | None = None
305
+ username: str | None = None
306
+ size_original: int
307
+ size_compressed: int
308
+ sha256: str
309
+ created_at: datetime
310
+
311
+
312
+ class BndbQueryRequest(BaseModel):
313
+ name: str | None = None
314
+ limit: int | None = Field(None, ge=1, le=200)
315
+ page: int | None = Field(None, ge=1)