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
48 changes: 48 additions & 0 deletions .github/workflows/wraithrun-scan.example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: WraithRun Security Scan

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
# Nightly host triage at 02:00 UTC
- cron: '0 2 * * *'
workflow_dispatch:

permissions:
contents: read

jobs:
scan:
name: Security Investigation
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Run WraithRun scan
id: scan
uses: Shreyas582/wraithrun-action@v1
with:
task: 'Triage this host for persistence mechanisms and suspicious accounts'
format: json
max-steps: 10
fail-on-severity: high

- name: Upload report artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: wraithrun-report
path: ${{ steps.scan.outputs.report-path }}

- name: Summary
if: always()
run: |
echo "## WraithRun Scan Results" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "- **Findings:** ${{ steps.scan.outputs.finding-count }}" >> "$GITHUB_STEP_SUMMARY"
echo "- **Max Severity:** ${{ steps.scan.outputs.max-severity }}" >> "$GITHUB_STEP_SUMMARY"
echo "- **Exit Code:** ${{ steps.scan.outputs.exit-code }}" >> "$GITHUB_STEP_SUMMARY"
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,21 @@ The format is inspired by Keep a Changelog and this project follows Semantic Ver

- (none yet)

## 1.2.0 - 2026-04-05
## 1.3.0 - 2026-04-12

### Added

- **CI/CD pipeline integration** (#103): first-party GitHub composite Action (`Shreyas582/wraithrun-action@v1`) with version resolution, binary caching, cross-platform install, scan execution, and JSON finding extraction. Also ships GitLab CI template, generic shell script for Jenkins/CircleCI, and an example GitHub Actions workflow.
- **CI integration guide** (`docs/ci-integration.md`): step-by-step docs for GitHub Actions, GitLab CI, and generic shell usage, covering exit code policy, output formats, scheduled scanning, and interpreting results.
- **`ExecutionProviderBackend` trait** (#47): hardware-agnostic backend abstraction in `inference_bridge::backend` with `name()`, `is_available()`, `priority()`, `build_session()`, and `diagnose()` methods. Includes `DiagnosticEntry` type for doctor integration and `InferenceSession` trait for provider-created sessions.
- **`ProviderRegistry`** (#48): runtime registry with `discover()`, `best_available()`, `get()`, `list()`, and `build_session_with_fallback()`. Auto-selects highest-priority available backend with cascading fallback on session init failure.
- **Built-in CPU backend**: always-available CPU execution provider (priority 0) with dry-run support and ONNX Runtime CPU session bridging.
- **Built-in Vitis backend** (cfg-gated): AMD Vitis AI NPU provider (priority 300, `vitis` feature) with environment-based availability detection and diagnostic checks.
- 12 new unit tests for backend trait, registry, and session functionality (245 total).

### Changed

- `inference_bridge` crate now exports `pub mod backend` alongside `pub mod onnx_vitis`.

### Added

Expand Down
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ resolver = "2"

[workspace.package]
edition = "2021"
version = "1.2.0"
version = "1.3.0"
license = "MIT"

[workspace.dependencies]
Expand Down
174 changes: 174 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
name: 'WraithRun Security Scan'
description: 'Run a WraithRun automated security investigation in your CI pipeline'
author: 'Shreyas582'

branding:
icon: 'shield'
color: 'purple'

inputs:
version:
description: 'WraithRun version to install (e.g. "1.2.0" or "latest")'
required: false
default: 'latest'
task:
description: 'Investigation task description'
required: true
profile:
description: 'Named configuration profile'
required: false
default: ''
max-steps:
description: 'Maximum agent investigation steps'
required: false
default: '10'
format:
description: 'Output format: json, summary, markdown, narrative'
required: false
default: 'json'
fail-on-severity:
description: 'Fail the step if any finding meets or exceeds this severity (none, info, low, medium, high, critical)'
required: false
default: 'none'
extra-args:
description: 'Additional CLI arguments passed to wraithrun'
required: false
default: ''

outputs:
report-path:
description: 'Path to the generated report file'
value: ${{ steps.run.outputs.report_path }}
finding-count:
description: 'Total number of findings'
value: ${{ steps.run.outputs.finding_count }}
max-severity:
description: 'Highest severity finding (or "none")'
value: ${{ steps.run.outputs.max_severity }}
exit-code:
description: 'Exit code from the WraithRun scan'
value: ${{ steps.run.outputs.exit_code }}

runs:
using: 'composite'
steps:
- name: Determine version
id: version
shell: bash
run: |
if [ "${{ inputs.version }}" = "latest" ]; then
VERSION=$(curl -sS https://api.github.com/repos/Shreyas582/WraithRun/releases/latest | grep '"tag_name"' | head -1 | sed 's/.*"v\(.*\)".*/\1/')
echo "resolved=${VERSION}" >> "$GITHUB_OUTPUT"
else
echo "resolved=${{ inputs.version }}" >> "$GITHUB_OUTPUT"
fi

- name: Cache WraithRun binary
id: cache
uses: actions/cache@v4
with:
path: ~/.wraithrun-bin
key: wraithrun-${{ runner.os }}-${{ steps.version.outputs.resolved }}

- name: Install WraithRun
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
run: |
set -euo pipefail
VERSION="${{ steps.version.outputs.resolved }}"
mkdir -p ~/.wraithrun-bin

case "${{ runner.os }}" in
Linux)
ASSET="wraithrun-${VERSION}-x86_64-unknown-linux-gnu.tar.gz"
curl -sSL "https://github.com/Shreyas582/WraithRun/releases/download/v${VERSION}/${ASSET}" -o /tmp/wraithrun.tar.gz
tar -xzf /tmp/wraithrun.tar.gz -C ~/.wraithrun-bin
;;
macOS)
ASSET="wraithrun-${VERSION}-x86_64-apple-darwin.tar.gz"
curl -sSL "https://github.com/Shreyas582/WraithRun/releases/download/v${VERSION}/${ASSET}" -o /tmp/wraithrun.tar.gz
tar -xzf /tmp/wraithrun.tar.gz -C ~/.wraithrun-bin
;;
Windows)
ASSET="wraithrun-${VERSION}-x86_64-pc-windows-msvc.zip"
curl -sSL "https://github.com/Shreyas582/WraithRun/releases/download/v${VERSION}/${ASSET}" -o "$TEMP/wraithrun.zip"
unzip -o "$TEMP/wraithrun.zip" -d ~/.wraithrun-bin
;;
esac

- name: Add to PATH
shell: bash
run: echo "$HOME/.wraithrun-bin" >> "$GITHUB_PATH"

- name: Run WraithRun scan
id: run
shell: bash
run: |
set -uo pipefail
REPORT_PATH="${{ runner.temp }}/wraithrun-report.json"

# Build CLI arguments
ARGS=(--task "${{ inputs.task }}" --format "${{ inputs.format }}" --max-steps "${{ inputs.max-steps }}")

if [ -n "${{ inputs.profile }}" ]; then
ARGS+=(--profile "${{ inputs.profile }}")
fi

# Exit policy
if [ "${{ inputs.fail-on-severity }}" != "none" ]; then
ARGS+=(--exit-policy severity-threshold --exit-threshold "${{ inputs.fail-on-severity }}")
fi

# Extra user args
if [ -n "${{ inputs.extra-args }}" ]; then
# shellcheck disable=SC2206
ARGS+=(${{ inputs.extra-args }})
fi

# Run and capture exit code
EXIT_CODE=0
wraithrun "${ARGS[@]}" > "$REPORT_PATH" 2>&1 || EXIT_CODE=$?

# Extract finding count and max severity from JSON report
FINDING_COUNT=0
MAX_SEVERITY="none"
if [ -f "$REPORT_PATH" ] && command -v python3 &>/dev/null; then
FINDING_COUNT=$(python3 -c "
import json, sys
try:
data = json.load(open('$REPORT_PATH'))
findings = data.get('findings', []) + data.get('supplementary_findings', [])
print(len(findings))
except Exception:
print(0)
" 2>/dev/null || echo 0)

MAX_SEVERITY=$(python3 -c "
import json, sys
try:
data = json.load(open('$REPORT_PATH'))
findings = data.get('findings', []) + data.get('supplementary_findings', [])
order = {'critical':5,'high':4,'medium':3,'low':2,'info':1}
best = 0
best_name = 'none'
for f in findings:
sev = f.get('severity','info').lower()
if order.get(sev,0) > best:
best = order[sev]
best_name = sev
print(best_name)
except Exception:
print('none')
" 2>/dev/null || echo "none")
fi

echo "report_path=${REPORT_PATH}" >> "$GITHUB_OUTPUT"
echo "finding_count=${FINDING_COUNT}" >> "$GITHUB_OUTPUT"
echo "max_severity=${MAX_SEVERITY}" >> "$GITHUB_OUTPUT"
echo "exit_code=${EXIT_CODE}" >> "$GITHUB_OUTPUT"

# Fail the step if exit code is non-zero and severity policy is active
if [ "$EXIT_CODE" -ne 0 ] && [ "${{ inputs.fail-on-severity }}" != "none" ]; then
echo "::error::WraithRun found findings at or above '${{ inputs.fail-on-severity }}' severity (exit code ${EXIT_CODE})"
exit "$EXIT_CODE"
fi
42 changes: 42 additions & 0 deletions ci-templates/gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# GitLab CI template for WraithRun security scanning.
# Include this in your .gitlab-ci.yml:
# include:
# - remote: https://raw.githubusercontent.com/Shreyas582/WraithRun/main/ci-templates/gitlab-ci.yml

wraithrun-scan:
stage: test
image: ubuntu:22.04
variables:
WRAITHRUN_VERSION: "latest"
WRAITHRUN_TASK: "Triage this host for persistence mechanisms and suspicious accounts"
WRAITHRUN_FORMAT: "json"
WRAITHRUN_MAX_STEPS: "10"
WRAITHRUN_FAIL_SEVERITY: "none"
before_script:
- apt-get update -qq && apt-get install -y -qq curl python3 > /dev/null
- |
if [ "$WRAITHRUN_VERSION" = "latest" ]; then
WRAITHRUN_VERSION=$(curl -sS https://api.github.com/repos/Shreyas582/WraithRun/releases/latest | grep '"tag_name"' | head -1 | sed 's/.*"v\(.*\)".*/\1/')
fi
- curl -sSL "https://github.com/Shreyas582/WraithRun/releases/download/v${WRAITHRUN_VERSION}/wraithrun-${WRAITHRUN_VERSION}-x86_64-unknown-linux-gnu.tar.gz" -o /tmp/wraithrun.tar.gz
- tar -xzf /tmp/wraithrun.tar.gz -C /usr/local/bin
script:
- |
ARGS="--task \"${WRAITHRUN_TASK}\" --format ${WRAITHRUN_FORMAT} --max-steps ${WRAITHRUN_MAX_STEPS}"
if [ "$WRAITHRUN_FAIL_SEVERITY" != "none" ]; then
ARGS="${ARGS} --exit-policy severity-threshold --exit-threshold ${WRAITHRUN_FAIL_SEVERITY}"
fi
eval wraithrun ${ARGS} > wraithrun-report.json 2>&1 || EXIT_CODE=$?
echo "Exit code: ${EXIT_CODE:-0}"
if [ "${EXIT_CODE:-0}" -ne 0 ] && [ "$WRAITHRUN_FAIL_SEVERITY" != "none" ]; then
exit ${EXIT_CODE}
fi
artifacts:
when: always
paths:
- wraithrun-report.json
expire_in: 30 days
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "schedule"
Loading
Loading