Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Performance: [metrics if applicable]
- [ ] Code follows project style guidelines (`cargo fmt`)
- [ ] No clippy warnings (`cargo clippy --workspace --all-targets -- -D warnings`)
- [ ] All tests pass (`cargo test --workspace`)
- [ ] MSRV compatibility maintained (Rust 1.95+)
- [ ] MSRV compatibility maintained (Rust 1.99.1+)
- [ ] Documentation updated (if needed):
- [ ] README.md statistics/features updated
- [ ] CHANGELOG.md entry added
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,13 @@ jobs:
run: |
# Download and extract Npcap SDK (contains Packet.lib for development)
Write-Host "Downloading Npcap SDK..."
curl -L -o npcap-sdk.zip https://npcap.com/dist/npcap-sdk-1.13.zip
curl -fL -o npcap-sdk.zip https://npcap.com/dist/npcap-sdk-1.13.zip
Expand-Archive -Path npcap-sdk.zip -DestinationPath npcap-sdk
Write-Host "✓ Npcap SDK extracted"

# Download Npcap installer and extract DLLs without running (avoids hang)
Write-Host "`nDownloading Npcap 1.79 installer..."
curl -L -o npcap-installer.exe https://npcap.com/dist/npcap-1.79.exe
curl -fL -o npcap-installer.exe https://npcap.com/dist/npcap-1.79.exe

# Extract installer using 7zip (pre-installed on GitHub Actions)
Write-Host "Extracting DLLs from Npcap installer (no execution)..."
Expand Down Expand Up @@ -366,19 +366,19 @@ jobs:

# Job 6: MSRV (Minimum Supported Rust Version) check
msrv:
name: MSRV Check (1.95)
name: MSRV Check (1.99.1)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- name: Install Rust 1.95
- name: Install Rust 1.99.1
# NOT an action version -- this ref selects the Rust toolchain, and it
# must stay equal to `rust-version` in Cargo.toml. Dependabot proposed
# bumping it to 1.100, which would have left the job named "Install
# Rust 1.95" while installing 1.100, so the MSRV gate would pass
# Rust 1.99.1" while installing 1.100, so the MSRV gate would pass
# without ever testing the floor it claims to enforce. Ignored in
# .github/dependabot.yml.
uses: dtolnay/rust-toolchain@1.95
uses: dtolnay/rust-toolchain@1.99.1

- name: Install system dependencies
run: sudo apt-get update && sudo apt-get install -y libpcap-dev pkg-config
Expand Down
68 changes: 60 additions & 8 deletions .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,67 @@ env:
CARGO_TERM_COLOR: always

jobs:
resolve-targets:
name: Resolve Fuzz Targets
runs-on: ubuntu-latest
outputs:
targets: ${{ steps.resolve.outputs.targets }}
steps:
- name: Validate and resolve targets
id: resolve
env:
TARGETS_INPUT: ${{ github.event.inputs.targets || 'all' }}
run: |
KNOWN_TARGETS=("fuzz_tcp_parser" "fuzz_udp_parser" "fuzz_ipv6_parser" "fuzz_icmpv6_parser" "fuzz_tls_parser")
INPUT="$(echo "$TARGETS_INPUT" | tr -d '[:space:]')"
if [ -z "$INPUT" ] || [ "$INPUT" = "all" ]; then
SELECTED=("${KNOWN_TARGETS[@]}")
else
IFS=',' read -r -a REQUESTED <<< "$INPUT"
SELECTED=()
for req in "${REQUESTED[@]}"; do
if [ -z "$req" ]; then
continue
fi
FOUND=false
for known in "${KNOWN_TARGETS[@]}"; do
if [ "$req" = "$known" ]; then
FOUND=true
break
fi
done
if [ "$FOUND" != "true" ]; then
echo "::error::Unknown fuzz target '$req'. Known targets: ${KNOWN_TARGETS[*]} (or 'all')"
exit 1
fi
ALREADY_SELECTED=false
for sel in "${SELECTED[@]}"; do
if [ "$req" = "$sel" ]; then
ALREADY_SELECTED=true
break
fi
done
if [ "$ALREADY_SELECTED" != "true" ]; then
SELECTED+=("$req")
fi
done
if [ "${#SELECTED[@]}" -eq 0 ]; then
echo "::error::targets input did not specify any valid fuzz targets: $TARGETS_INPUT"
exit 1
fi
fi
TARGETS_JSON=$(printf '%s\n' "${SELECTED[@]}" | jq -R . | jq -sc .)
echo "targets=$TARGETS_JSON" >> "$GITHUB_OUTPUT"

fuzz:
name: Fuzz ${{ matrix.target }}
runs-on: ubuntu-latest
needs: resolve-targets

strategy:
fail-fast: false # Continue fuzzing other targets even if one crashes
matrix:
target:
- fuzz_tcp_parser
- fuzz_udp_parser
- fuzz_ipv6_parser
- fuzz_icmpv6_parser
- fuzz_tls_parser
target: ${{ fromJSON(needs.resolve-targets.outputs.targets) }}

steps:
- name: Checkout repository
Expand All @@ -63,7 +111,7 @@ jobs:
- name: Cache target directory
uses: actions/cache@v6
with:
path: target
path: fuzz/target
key: ${{ runner.os }}-fuzz-target-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-fuzz-target-${{ matrix.target }}-
Expand Down Expand Up @@ -226,18 +274,22 @@ jobs:
summary:
name: Fuzzing Summary
runs-on: ubuntu-latest
needs: fuzz
needs:
- resolve-targets
- fuzz
if: always()

steps:
- name: Generate summary
env:
DURATION_INPUT: ${{ github.event.inputs.duration || '600' }}
TARGETS_INPUT: ${{ github.event.inputs.targets || 'all' }}
run: |
echo "## Fuzzing Run Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Date:** $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
echo "**Duration:** ${DURATION_INPUT} seconds per target" >> $GITHUB_STEP_SUMMARY
echo "**Targets:** ${TARGETS_INPUT}" >> $GITHUB_STEP_SUMMARY
echo "**Trigger:** ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "All fuzz targets executed. Check individual job outputs for statistics." >> $GITHUB_STEP_SUMMARY
Expand Down
27 changes: 23 additions & 4 deletions .github/workflows/gemini-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,27 +73,44 @@ jobs:
id: 'mint_identity_token'
if: |-
${{ vars.APP_ID }}
uses: 'actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1' # ratchet:actions/create-github-app-token@v3.2.0
uses: 'actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510' # ratchet:actions/create-github-app-token@v3.3.0
with:
app-id: '${{ vars.APP_ID }}'
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
permission-contents: 'read'
permission-issues: 'write'
permission-pull-requests: 'write'

- name: 'Check Gemini credentials'
id: 'check_credentials'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
GOOGLE_API_KEY: '${{ secrets.GOOGLE_API_KEY }}'
GCP_WIF_PROVIDER: '${{ vars.GCP_WIF_PROVIDER }}'
run: |-
if [ -n "${GEMINI_API_KEY}${GOOGLE_API_KEY}${GCP_WIF_PROVIDER}" ]; then
echo "configured=true" >> "${GITHUB_OUTPUT}"
else
echo "::notice::Skipping Gemini CLI dispatch: no GEMINI_API_KEY, GOOGLE_API_KEY, or GCP_WIF_PROVIDER configured."
echo "configured=false" >> "${GITHUB_OUTPUT}"
fi

- name: 'Extract command'
id: 'extract_command'
uses: 'actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3' # ratchet:actions/github-script@v9.0.0
env:
EVENT_TYPE: '${{ github.event_name }}.${{ github.event.action }}'
REQUEST: '${{ github.event.comment.body || github.event.review.body || github.event.issue.body }}'
GEMINI_CONFIGURED: '${{ steps.check_credentials.outputs.configured }}'
with:
script: |
const request = process.env.REQUEST;
const request = process.env.REQUEST || '';
const eventType = process.env.EVENT_TYPE
core.setOutput('request', request);

if (request.startsWith("@gemini-cli /review")) {
if (process.env.GEMINI_CONFIGURED !== 'true') {
core.setOutput('command', 'skip');
} else if (request.startsWith("@gemini-cli /review")) {
core.setOutput('command', 'review');
const additionalContext = request.replace(/^@gemini-cli \/review/, '').trim();
core.setOutput('additional_context', additionalContext);
Expand All @@ -112,6 +129,8 @@ jobs:
}

- name: 'Acknowledge request'
if: |-
${{ steps.extract_command.outputs.command != 'skip' && steps.extract_command.outputs.command != 'fallthrough' }}
env:
GITHUB_TOKEN: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
ISSUE_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
Expand Down Expand Up @@ -183,7 +202,7 @@ jobs:
id: 'mint_identity_token'
if: |-
${{ vars.APP_ID }}
uses: 'actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1' # ratchet:actions/create-github-app-token@v3.2.0
uses: 'actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510' # ratchet:actions/create-github-app-token@v3.3.0
with:
app-id: '${{ vars.APP_ID }}'
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
Expand Down
18 changes: 17 additions & 1 deletion .github/workflows/gemini-invoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,32 @@ jobs:
id: 'mint_identity_token'
if: |-
${{ vars.APP_ID }}
uses: 'actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1' # ratchet:actions/create-github-app-token@v3.2.0
uses: 'actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510' # ratchet:actions/create-github-app-token@v3.3.0
with:
app-id: '${{ vars.APP_ID }}'
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
permission-contents: 'read'
permission-issues: 'write'
permission-pull-requests: 'write'

- name: 'Check Gemini credentials'
id: 'check_credentials'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
GOOGLE_API_KEY: '${{ secrets.GOOGLE_API_KEY }}'
GCP_WIF_PROVIDER: '${{ vars.GCP_WIF_PROVIDER }}'
run: |-
if [ -n "${GEMINI_API_KEY}${GOOGLE_API_KEY}${GCP_WIF_PROVIDER}" ]; then
echo "configured=true" >> "${GITHUB_OUTPUT}"
else
echo "::notice::Skipping Gemini CLI invocation: no GEMINI_API_KEY, GOOGLE_API_KEY, or GCP_WIF_PROVIDER configured."
echo "configured=false" >> "${GITHUB_OUTPUT}"
fi

- name: 'Run Gemini CLI'
id: 'run_gemini'
if: |-
${{ steps.check_credentials.outputs.configured == 'true' }}
uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
env:
TITLE: '${{ github.event.pull_request.title || github.event.issue.title }}'
Expand Down
20 changes: 19 additions & 1 deletion .github/workflows/gemini-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,36 @@ jobs:
id: 'mint_identity_token'
if: |-
${{ vars.APP_ID }}
uses: 'actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1' # ratchet:actions/create-github-app-token@v3.2.0
uses: 'actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510' # ratchet:actions/create-github-app-token@v3.3.0
with:
app-id: '${{ vars.APP_ID }}'
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
permission-contents: 'read'
permission-issues: 'write'
permission-pull-requests: 'write'

- name: 'Check Gemini credentials'
id: 'check_credentials'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
GOOGLE_API_KEY: '${{ secrets.GOOGLE_API_KEY }}'
GCP_WIF_PROVIDER: '${{ vars.GCP_WIF_PROVIDER }}'
run: |-
if [ -n "${GEMINI_API_KEY}${GOOGLE_API_KEY}${GCP_WIF_PROVIDER}" ]; then
echo "configured=true" >> "${GITHUB_OUTPUT}"
else
echo "::notice::Skipping Gemini PR review: no GEMINI_API_KEY, GOOGLE_API_KEY, or GCP_WIF_PROVIDER configured."
echo "configured=false" >> "${GITHUB_OUTPUT}"
fi

- name: 'Checkout repository'
if: |-
${{ steps.check_credentials.outputs.configured == 'true' }}
uses: 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' # ratchet:actions/checkout@v7.0.1

- name: 'Run Gemini pull request review'
if: |-
${{ steps.check_credentials.outputs.configured == 'true' }}
uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
id: 'gemini_pr_review'
env:
Expand Down
18 changes: 16 additions & 2 deletions .github/workflows/gemini-scheduled-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,24 @@ jobs:
ISSUE_COUNT="$(echo "${ISSUES}" | jq 'length')"
echo "✅ Found ${ISSUE_COUNT} issue(s) to triage! 🎯"

- name: 'Check Gemini credentials'
id: 'check_credentials'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
GOOGLE_API_KEY: '${{ secrets.GOOGLE_API_KEY }}'
GCP_WIF_PROVIDER: '${{ vars.GCP_WIF_PROVIDER }}'
run: |-
if [ -n "${GEMINI_API_KEY}${GOOGLE_API_KEY}${GCP_WIF_PROVIDER}" ]; then
echo "configured=true" >> "${GITHUB_OUTPUT}"
else
echo "::notice::Skipping Gemini scheduled issue analysis: no GEMINI_API_KEY, GOOGLE_API_KEY, or GCP_WIF_PROVIDER configured."
echo "configured=false" >> "${GITHUB_OUTPUT}"
fi

- name: 'Run Gemini Issue Analysis'
id: 'gemini_issue_analysis'
if: |-
${{ steps.find_issues.outputs.issues_to_triage != '[]' }}
${{ steps.check_credentials.outputs.configured == 'true' && steps.find_issues.outputs.issues_to_triage != '[]' }}
uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
env:
GITHUB_TOKEN: '' # Do not pass any auth token here since this runs on untrusted inputs
Expand Down Expand Up @@ -250,7 +264,7 @@ jobs:
id: 'mint_identity_token'
if: |-
${{ vars.APP_ID }}
uses: 'actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1' # ratchet:actions/create-github-app-token@v3.2.0
uses: 'actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510' # ratchet:actions/create-github-app-token@v3.3.0
with:
app-id: '${{ vars.APP_ID }}'
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
Expand Down
18 changes: 16 additions & 2 deletions .github/workflows/gemini-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,24 @@ jobs:
core.info(`Found ${labelNames.length} labels: ${labelNames.join(', ')}`);
return labelNames;

- name: 'Check Gemini credentials'
id: 'check_credentials'
env:
GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
GOOGLE_API_KEY: '${{ secrets.GOOGLE_API_KEY }}'
GCP_WIF_PROVIDER: '${{ vars.GCP_WIF_PROVIDER }}'
run: |-
if [ -n "${GEMINI_API_KEY}${GOOGLE_API_KEY}${GCP_WIF_PROVIDER}" ]; then
echo "configured=true" >> "${GITHUB_OUTPUT}"
else
echo "::notice::Skipping Gemini issue analysis: no GEMINI_API_KEY, GOOGLE_API_KEY, or GCP_WIF_PROVIDER configured."
echo "configured=false" >> "${GITHUB_OUTPUT}"
fi

- name: 'Run Gemini issue analysis'
id: 'gemini_analysis'
if: |-
${{ steps.get_labels.outputs.available_labels != '' }}
${{ steps.check_credentials.outputs.configured == 'true' && steps.get_labels.outputs.available_labels != '' }}
uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
env:
GITHUB_TOKEN: '' # Do NOT pass any auth tokens here since this runs on untrusted inputs
Expand Down Expand Up @@ -158,7 +172,7 @@ jobs:
id: 'mint_identity_token'
if: |-
${{ vars.APP_ID }}
uses: 'actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1' # ratchet:actions/create-github-app-token@v3.2.0
uses: 'actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510' # ratchet:actions/create-github-app-token@v3.3.0
with:
app-id: '${{ vars.APP_ID }}'
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -301,11 +301,11 @@ jobs:
if: matrix.os == 'windows-latest'
run: |
# Download and extract Npcap SDK (contains Packet.lib for development)
curl -L -o npcap-sdk.zip https://npcap.com/dist/npcap-sdk-1.13.zip
curl -fL -o npcap-sdk.zip https://npcap.com/dist/npcap-sdk-1.13.zip
Expand-Archive -Path npcap-sdk.zip -DestinationPath npcap-sdk

# Download Npcap installer and extract DLLs without running (avoids hang)
curl -L -o npcap-installer.exe https://npcap.com/dist/npcap-1.79.exe
curl -fL -o npcap-installer.exe https://npcap.com/dist/npcap-1.79.exe

# Extract installer using 7zip (pre-installed on GitHub Actions)
7z x npcap-installer.exe -o"npcap-runtime" -y
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ ProRT-IP project guidance for Claude Code.
## Critical Dependencies

```toml
tokio = "1.35" # Async runtime
tokio = "1.54" # Async runtime
pnet = "0.35" # Packets
clap = "4.5" # CLI
sqlx = "0.8" # Async SQL (0.9 needs Rust 1.94, above the 1.88 MSRV)
clap = "4.6" # CLI
sqlx = "0.9" # Async SQL
ratatui = "0.30" # TUI
```

Expand Down
Loading
Loading