Skip to content

Commit 28e4603

Browse files
Merge pull request #2643 from blacklanternsecurity/3.0-update
Dev -> 3.0 Sync
2 parents 98087bd + 43936a1 commit 28e4603

84 files changed

Lines changed: 5169 additions & 2430 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/benchmark.yml

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
name: Performance Benchmarks
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'bbot/**/*.py'
7+
- 'pyproject.toml'
8+
- '.github/workflows/benchmark.yml'
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
12+
cancel-in-progress: true
13+
14+
permissions:
15+
contents: read
16+
pull-requests: write
17+
18+
jobs:
19+
benchmark:
20+
runs-on: ubuntu-latest
21+
22+
steps:
23+
- uses: actions/checkout@v5
24+
with:
25+
fetch-depth: 0 # Need full history for branch comparison
26+
27+
- name: Set up Python
28+
uses: actions/setup-python@v6
29+
with:
30+
python-version: "3.11"
31+
32+
- name: Install dependencies
33+
run: |
34+
pip install poetry
35+
poetry install --with dev
36+
37+
- name: Install system dependencies
38+
run: |
39+
sudo apt-get update
40+
sudo apt-get install -y libmagic1
41+
42+
# Generate benchmark comparison report using our branch-based script
43+
- name: Generate benchmark comparison report
44+
run: |
45+
poetry run python bbot/scripts/benchmark_report.py \
46+
--base ${{ github.base_ref }} \
47+
--current ${{ github.head_ref }} \
48+
--output benchmark_report.md \
49+
--keep-results
50+
continue-on-error: true
51+
52+
# Upload benchmark results as artifacts
53+
- name: Upload benchmark results
54+
uses: actions/upload-artifact@v4
55+
with:
56+
name: benchmark-results
57+
path: |
58+
benchmark_report.md
59+
base_benchmark_results.json
60+
current_benchmark_results.json
61+
retention-days: 30
62+
63+
# Comment on PR with benchmark results
64+
- name: Comment benchmark results on PR
65+
uses: actions/github-script@v8
66+
with:
67+
script: |
68+
const fs = require('fs');
69+
70+
try {
71+
const report = fs.readFileSync('benchmark_report.md', 'utf8');
72+
73+
// Find existing benchmark comment (with pagination)
74+
const comments = await github.rest.issues.listComments({
75+
owner: context.repo.owner,
76+
repo: context.repo.repo,
77+
issue_number: context.issue.number,
78+
per_page: 100, // Get more comments per page
79+
});
80+
81+
// Debug: log all comments to see what we're working with
82+
console.log(`Found ${comments.data.length} comments on this PR`);
83+
comments.data.forEach((comment, index) => {
84+
console.log(`Comment ${index}: user=${comment.user.login}, body preview="${comment.body.substring(0, 100)}..."`);
85+
});
86+
87+
const existingComments = comments.data.filter(comment =>
88+
comment.body.toLowerCase().includes('performance benchmark') &&
89+
comment.user.login === 'github-actions[bot]'
90+
);
91+
92+
console.log(`Found ${existingComments.length} existing benchmark comments`);
93+
94+
if (existingComments.length > 0) {
95+
// Sort comments by creation date to find the most recent
96+
const sortedComments = existingComments.sort((a, b) =>
97+
new Date(b.created_at) - new Date(a.created_at)
98+
);
99+
100+
const mostRecentComment = sortedComments[0];
101+
console.log(`Updating most recent benchmark comment: ${mostRecentComment.id} (created: ${mostRecentComment.created_at})`);
102+
103+
await github.rest.issues.updateComment({
104+
owner: context.repo.owner,
105+
repo: context.repo.repo,
106+
comment_id: mostRecentComment.id,
107+
body: report
108+
});
109+
console.log('Updated existing benchmark comment');
110+
111+
// Delete any older duplicate comments
112+
if (existingComments.length > 1) {
113+
console.log(`Deleting ${existingComments.length - 1} older duplicate comments`);
114+
for (let i = 1; i < sortedComments.length; i++) {
115+
const commentToDelete = sortedComments[i];
116+
console.log(`Attempting to delete comment ${commentToDelete.id} (created: ${commentToDelete.created_at})`);
117+
118+
try {
119+
await github.rest.issues.deleteComment({
120+
owner: context.repo.owner,
121+
repo: context.repo.repo,
122+
comment_id: commentToDelete.id
123+
});
124+
console.log(`Successfully deleted duplicate comment: ${commentToDelete.id}`);
125+
} catch (error) {
126+
console.error(`Failed to delete comment ${commentToDelete.id}: ${error.message}`);
127+
console.error(`Error details:`, error);
128+
}
129+
}
130+
}
131+
} else {
132+
// Create new comment
133+
await github.rest.issues.createComment({
134+
owner: context.repo.owner,
135+
repo: context.repo.repo,
136+
issue_number: context.issue.number,
137+
body: report
138+
});
139+
console.log('Created new benchmark comment');
140+
}
141+
} catch (error) {
142+
console.error('Failed to post benchmark results:', error);
143+
144+
// Post a fallback comment
145+
const fallbackMessage = [
146+
'## Performance Benchmark Report',
147+
'',
148+
'> ⚠️ **Failed to generate detailed benchmark comparison**',
149+
'> ',
150+
'> The benchmark comparison failed to run. This might be because:',
151+
'> - Benchmark tests don\'t exist on the base branch yet',
152+
'> - Dependencies are missing',
153+
'> - Test execution failed',
154+
'> ',
155+
'> Please check the [workflow logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.',
156+
'> ',
157+
'> 📁 Benchmark artifacts may be available for download from the workflow run.'
158+
].join('\\n');
159+
160+
await github.rest.issues.createComment({
161+
owner: context.repo.owner,
162+
repo: context.repo.repo,
163+
issue_number: context.issue.number,
164+
body: fallbackMessage
165+
});
166+
}

.github/workflows/codeql.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ jobs:
5555
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
5656
steps:
5757
- name: Checkout repository
58-
uses: actions/checkout@v4
58+
uses: actions/checkout@v5
5959

6060
# Add any setup steps before running the `github/codeql-action/init` action.
6161
# This includes steps like installing compilers or runtimes (`actions/setup-node`

.github/workflows/distro_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
matrix:
1717
os: ["ubuntu:22.04", "ubuntu:24.04", "debian", "archlinux", "fedora", "kalilinux/kali-rolling", "parrotsec/security"]
1818
steps:
19-
- uses: actions/checkout@v4
19+
- uses: actions/checkout@v5
2020
- name: Install Python and Poetry
2121
run: |
2222
if [ -f /etc/os-release ]; then

.github/workflows/docs_updater.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ jobs:
99
update_docs:
1010
runs-on: ubuntu-latest
1111
steps:
12-
- uses: actions/checkout@v4
12+
- uses: actions/checkout@v5
1313
with:
1414
token: ${{ secrets.BBOT_DOCS_UPDATER_PAT }}
1515
ref: dev # Checkout the dev branch
1616
- name: Set up Python
17-
uses: actions/setup-python@v5
17+
uses: actions/setup-python@v6
1818
with:
1919
python-version: "3.x"
2020
- name: Install dependencies

.github/workflows/tests.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ jobs:
1919
matrix:
2020
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
2121
steps:
22-
- uses: actions/checkout@v4
22+
- uses: actions/checkout@v5
2323
- name: Set up Python
24-
uses: actions/setup-python@v5
24+
uses: actions/setup-python@v6
2525
with:
2626
python-version: ${{ matrix.python-version }}
2727
- name: Set Python Version Environment Variable
@@ -55,11 +55,11 @@ jobs:
5555
if: github.event_name == 'push' && (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/stable')
5656
continue-on-error: true
5757
steps:
58-
- uses: actions/checkout@v4
58+
- uses: actions/checkout@v5
5959
with:
6060
fetch-depth: 0
6161
- name: Set up Python
62-
uses: actions/setup-python@v5
62+
uses: actions/setup-python@v6
6363
with:
6464
python-version: "3.x"
6565
- name: Install dependencies
@@ -72,7 +72,7 @@ jobs:
7272
run: python -m build
7373
- name: Publish Pypi package
7474
if: github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev'
75-
uses: pypa/gh-action-pypi-publish@release/v1
75+
uses: pypa/gh-action-pypi-publish@release/v1.13
7676
with:
7777
password: ${{ secrets.PYPI_API_TOKEN }}
7878
- name: Get BBOT version
@@ -107,10 +107,10 @@ jobs:
107107
runs-on: ubuntu-latest
108108
if: github.event_name == 'push' && (github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev')
109109
steps:
110-
- uses: actions/checkout@v4
110+
- uses: actions/checkout@v5
111111
with:
112112
token: ${{ secrets.BBOT_DOCS_UPDATER_PAT }}
113-
- uses: actions/setup-python@v5
113+
- uses: actions/setup-python@v6
114114
with:
115115
python-version: "3.11"
116116
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
@@ -151,7 +151,7 @@ jobs:
151151
# runs-on: ubuntu-latest
152152
# if: github.event_name == 'push' && github.ref == 'refs/heads/stable'
153153
# steps:
154-
# - uses: actions/checkout@v4
154+
# - uses: actions/checkout@v5
155155
# with:
156156
# ref: ${{ github.head_ref }}
157157
# fetch-depth: 0 # Fetch all history for all tags and branches

.github/workflows/version_updater.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ jobs:
99
update-nuclei-version:
1010
runs-on: ubuntu-latest
1111
steps:
12-
- uses: actions/checkout@v4
12+
- uses: actions/checkout@v5
1313
with:
1414
ref: dev
1515
fetch-depth: 0
1616
token: ${{ secrets.BBOT_DOCS_UPDATER_PAT }}
1717
- name: Set up Python
18-
uses: actions/setup-python@v5
18+
uses: actions/setup-python@v6
1919
with:
2020
python-version: '3.x'
2121
- name: Install dependencies
@@ -36,12 +36,12 @@ jobs:
3636
- name: Get current version
3737
id: get-current-version
3838
run: |
39-
version=$(grep -m 1 -oP '(?<=version": ")[^"]*' bbot/modules/deadly/nuclei.py)
39+
version=$(grep -m 1 -oP '(?<=version": ")[^"]*' bbot/modules/nuclei.py)
4040
echo "current_version=$version" >> $GITHUB_ENV
4141
- name: Update version
4242
id: update-version
4343
if: env.latest_version != env.current_version
44-
run: "sed -i '0,/\"version\": \".*\",/ s/\"version\": \".*\",/\"version\": \"${{ env.latest_version }}\",/g' bbot/modules/deadly/nuclei.py"
44+
run: "sed -i '0,/\"version\": \".*\",/ s/\"version\": \".*\",/\"version\": \"${{ env.latest_version }}\",/g' bbot/modules/nuclei.py"
4545
- name: Create pull request to update the version
4646
if: steps.update-version.outcome == 'success'
4747
uses: peter-evans/create-pull-request@v7
@@ -50,7 +50,7 @@ jobs:
5050
commit-message: "Update nuclei"
5151
title: "Update nuclei to ${{ env.latest_version }}"
5252
body: |
53-
This PR uses https://api.github.com/repos/projectdiscovery/nuclei/releases/latest to obtain the latest version of nuclei and update the version in bbot/modules/deadly/nuclei.py."
53+
This PR uses https://api.github.com/repos/projectdiscovery/nuclei/releases/latest to obtain the latest version of nuclei and update the version in bbot/modules/nuclei.py."
5454
5555
# Release notes:
5656
${{ env.release_notes }}
@@ -61,13 +61,13 @@ jobs:
6161
update-trufflehog-version:
6262
runs-on: ubuntu-latest
6363
steps:
64-
- uses: actions/checkout@v4
64+
- uses: actions/checkout@v5
6565
with:
6666
ref: dev
6767
fetch-depth: 0
6868
token: ${{ secrets.BBOT_DOCS_UPDATER_PAT }}
6969
- name: Set up Python
70-
uses: actions/setup-python@v5
70+
uses: actions/setup-python@v6
7171
with:
7272
python-version: '3.x'
7373
- name: Install dependencies

bbot/core/engine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ async def finished_tasks(self, tasks, timeout=None):
636636
"""
637637
if tasks:
638638
try:
639-
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED, timeout=timeout)
639+
done, _ = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED, timeout=timeout)
640640
return done
641641
except BaseException as e:
642642
if isinstance(e, (TimeoutError, asyncio.exceptions.TimeoutError)):

bbot/core/helpers/bloom.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import mmh3
33
import mmap
4+
import xxhash
45

56

67
class BloomFilter:
@@ -55,14 +56,12 @@ def _hashes(self, item):
5556
if not isinstance(item, str):
5657
item = str(item)
5758
item = item.encode("utf-8")
58-
return [abs(hash(item)) % self.size, abs(mmh3.hash(item)) % self.size, abs(self._fnv1a_hash(item)) % self.size]
5959

60-
def _fnv1a_hash(self, data):
61-
hash = 0x811C9DC5 # 2166136261
62-
for byte in data:
63-
hash ^= byte
64-
hash = (hash * 0x01000193) % 2**32 # 16777619
65-
return hash
60+
return [
61+
abs(hash(item)) % self.size,
62+
abs(mmh3.hash(item)) % self.size,
63+
abs(xxhash.xxh32(item).intdigest()) % self.size,
64+
]
6665

6766
def close(self):
6867
"""Explicitly close the memory-mapped file."""

0 commit comments

Comments
 (0)