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
36 changes: 36 additions & 0 deletions .github/workflows/binsync-compat-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# This workflow tests libbs compatibility with binsync
# It ensures that changes to libbs don't break binsync functionality

name: BinSync Compatibility Tests

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
binsync-tests:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up Python 3.10
uses: actions/setup-python@v2
with:
python-version: "3.10"
- name: Set branch name
run: echo "BRANCH_NAME=${GITHUB_HEAD_REF}" >> $GITHUB_ENV
- name: Install libbs from current branch
run: |
python -m pip install --upgrade pip
pip install .
- name: Install binsync and run its core tests
run: |
# Clone binsync and try to checkout the same branch if it exists
git clone https://github.com/binsync/binsync.git /tmp/binsync
cd /tmp/binsync
git checkout $BRANCH_NAME || true
pip install pytest .[extras]
# Run binsync core tests
pytest ./tests/test_client.py ./tests/test_state.py ./tests/test_auxiliary_server.py -v
4 changes: 1 addition & 3 deletions .github/workflows/core-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ name: Core Tests
on:
push:
branches: [ main ]
paths: ['libbs/artifacts/**', 'examples/**']
pull_request:
branches: [ main ]
paths: ['libbs/artifacts/**', 'examples/**']

jobs:
build:
Expand All @@ -33,4 +31,4 @@ jobs:

- name: Pytest
run: |
pytest ./tests/test_artifacts.py ./tests/test_cli.py
pytest ./tests/test_artifacts.py ./tests/test_cli.py -v
2 changes: 1 addition & 1 deletion libbs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "3.3.1"
__version__ = "3.3.2"


import logging
Expand Down
19 changes: 0 additions & 19 deletions libbs/plugin_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,22 +257,3 @@ def __init__(self, targets=None, target_install_paths=None):
def display_prologue(self):
print(textwrap.dedent("""
Now installing LibBS plugins for all supported decompilers..."""))

def install_ghidra(self, path=None, interactive=True):
ghidra_path = super().install_ghidra(path=path, interactive=interactive)
if ghidra_path is None:
return None

src_ghidra_libbs_pkg = self._libbs_plugins_path.joinpath("ghidra_libbs")
src_vendored = src_ghidra_libbs_pkg.joinpath("libbs_vendored")
src_script = src_ghidra_libbs_pkg.joinpath("ghidra_libbs.py")
src_script_shutdown = src_ghidra_libbs_pkg.joinpath("ghidra_libbs_shutdown.py")

dst_ghidra_libbs_pkg = ghidra_path.joinpath("libbs_vendored")
dst_ghidra_script = ghidra_path.joinpath("ghidra_libbs.py")
dst_script_shutdown = ghidra_path.joinpath("ghidra_libbs_shutdown.py")

self.link_or_copy(src_vendored, dst_ghidra_libbs_pkg, is_dir=True)
self.link_or_copy(src_script, dst_ghidra_script)
self.link_or_copy(src_script_shutdown, dst_script_shutdown)
return ghidra_path
70 changes: 70 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import sys
import subprocess
import tempfile
from pathlib import Path

import unittest

from libbs.plugin_installer import LibBSPluginInstaller


class TestCommandline(unittest.TestCase):
def test_change_watcher_plugin_cli(self):
Expand All @@ -15,5 +19,71 @@ def test_change_watcher_plugin_cli(self):
assert version == bs_change_watcher.__version__


class TestInstaller(unittest.TestCase):
"""Tests for the plugin installer."""

def test_install_ida_to_custom_path(self):
"""Test installing IDA plugin to a custom path."""
with tempfile.TemporaryDirectory() as tmpdir:
installer = LibBSPluginInstaller(targets=["ida"])
result = installer.install(interactive=False, paths_by_target={"ida": tmpdir})
# Verify the installer ran without error and returned the path
assert "ida" in installer._successful_installs
assert installer._successful_installs["ida"] == Path(tmpdir)

def test_install_binja_to_custom_path(self):
"""Test installing Binary Ninja plugin to a custom path."""
with tempfile.TemporaryDirectory() as tmpdir:
installer = LibBSPluginInstaller(targets=["binja"])
result = installer.install(interactive=False, paths_by_target={"binja": tmpdir})
# Verify the installer ran without error and returned the path
assert "binja" in installer._successful_installs
assert installer._successful_installs["binja"] == Path(tmpdir)

def test_install_ghidra_to_custom_path(self):
"""Test installing Ghidra plugin to a custom path."""
with tempfile.TemporaryDirectory() as tmpdir:
installer = LibBSPluginInstaller(targets=["ghidra"])
result = installer.install(interactive=False, paths_by_target={"ghidra": tmpdir})
# Verify the installer ran without error and returned the path
assert "ghidra" in installer._successful_installs
assert installer._successful_installs["ghidra"] == Path(tmpdir)

def test_install_angr_skipped_without_angrmanagement(self):
"""Test that angr install is skipped when angr-management is not installed."""
with tempfile.TemporaryDirectory() as tmpdir:
installer = LibBSPluginInstaller(targets=["angr"])
# angr install requires angr-management to be installed, so it should be skipped
# in test environments where angr-management is not available
result = installer.install(interactive=False, paths_by_target={"angr": tmpdir})
# The install may or may not succeed depending on whether angr-management is installed
# Just verify it doesn't raise an exception

def test_install_all_decompilers_to_custom_paths(self):
"""Test installing all decompilers to custom paths."""
with tempfile.TemporaryDirectory() as tmpdir:
ida_path = Path(tmpdir) / "ida"
binja_path = Path(tmpdir) / "binja"
ghidra_path = Path(tmpdir) / "ghidra"

ida_path.mkdir()
binja_path.mkdir()
ghidra_path.mkdir()

installer = LibBSPluginInstaller(targets=["ida", "binja", "ghidra"])
result = installer.install(
interactive=False,
paths_by_target={
"ida": str(ida_path),
"binja": str(binja_path),
"ghidra": str(ghidra_path),
}
)
# Verify all installers ran without error
assert "ida" in installer._successful_installs
assert "binja" in installer._successful_installs
assert "ghidra" in installer._successful_installs


if __name__ == "__main__":
unittest.main(argv=sys.argv)