Skip to content

Commit

Permalink
[SQUASH] Add Required v1 API Features With Tests & CI (#2)
Browse files Browse the repository at this point in the history
* marking v1

* Debug Mode

* Remove Local Database Feature

Local database management turned out to not be such a good idea. Why?
because now users can apply existing analysis in rizin and cutter
plugins and hence no need to track binary id or analysis id or hashes of
uploaded files.

If this new feature were not to be added, then local db management is a
very helpful feature to have IMO

* Log Now Available Globally

- Auth Check endpoint works
- Log object management removed, Log now available globally. Logging
will be initialized as soon as the library is loaded and all logs will
be stored in tmpdir.

* Auth Check Takes Host Param As Well

API key works correctly only with it's corresponding host. Auth check
now sets the host as well.

* Get AI Models

Add new endpoint to get available AI models

* Remove Redundant Model Arguments

Plugins now don't use a static modelname-version syntax to specify
versions. All AI model information is passed into the struct of
arguments of API that requires it.

* Mock API

* [BUG] Add Tests

There are some bugs found during execution of these tests
Strange, I never thought they'd exist like this. While writing
the tests I thought they'd be useless.

* Fix Some Memory Leaks

The bug still remains unfixed.

* [BUGFIX] Remove Free On Json String

The json string getter method does not duplicate the string
and hence ownership still remained with cJSON object. One of
the Json getter method destroyed the returned string and hence
it was a double-free bug, because in the end the cJSON object
tried to destroy it was well.

Phew!

* Update README For cJSON Dependency

Recently faced a RPATH issue when building and installing cJSON from
source on Mac OS. The updated README provides hints on how that can be
fixed.

* [HACK] Add CI Tests & Make Up For Poor Documentation

Documentation for `/v1/ann/symbol/batch` seems to be incorrect.
Can't wait for getting a response and then making decision based
on that, so for now moving ahead with a hack to optionally check
for `function_matches` field the second time. I'm referring
to the JSON response parsing code in Response.c

* Update ci.yaml To Run On Any Commit/Push

* CI Error Fix

* Update CI To Create TMP Directory & Display Logs

* To Review & Merge

Some small non-necessary fixes to follow a proper
coding style throughout.

* Use `memmove` in vec_remove

* `FREE` Automatically Sets To `NULL`

No need to explicitly sets variables to `NULL` after using `FREE` on
them, this is automatically done in `FREE` macro
  • Loading branch information
brightprogrammer authored Dec 20, 2024
1 parent c47ee65 commit 3412096
Show file tree
Hide file tree
Showing 28 changed files with 1,735 additions and 275,650 deletions.
49 changes: 49 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: CMake Build and Test

on:
push: # Trigger on any push to any branch
pull_request: # Trigger on any PR

jobs:
build-and-test:
runs-on: ubuntu-latest

steps:
# Checkout the repository
- name: Checkout code
uses: actions/checkout@v3

# Set up dependencies
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y cmake gcc g++ ninja-build libcurl4-openssl-dev pkg-config
# Configure the build
- name: Configure with CMake
run: |
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
# Build the project
- name: Build the project
run: |
ninja -C build
# Create temporary directory for logs
- name: Create temporary directory
run: |
export TMP=$(mktemp -d)
echo "Temporary directory created at $TMP"
echo "TMP=$TMP" >> $GITHUB_ENV
# Run tests
- name: Run tests
run: |
./build/bin/reai_test
# Output logs from the temporary directory
- name: Display logs
run: |
echo "Logs from $TMP:"
ls "$TMP"
cat "$TMP"/* || echo "No log files found"
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Build/
Build*/
build*/
.cache/
compile_commands.json
*.DS_Store
6 changes: 2 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.12)
project(CREAIT LANGUAGES C VERSION 0.1.1)
include(FetchContent)
include(ExternalProject)
include(CTest)

option(BUILD_SHARED_LIBS "Build using shared libraries" OFF)

Expand All @@ -11,10 +12,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIRBARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

set(CMAKE_C_STANDARD 23)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)

# generate a compile_commands.json for LSP clients
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

Expand All @@ -25,6 +22,7 @@ find_package(CURL REQUIRED)

# Add library source
add_subdirectory(Source)
add_subdirectory(Test)

# Add installation target for include files
install(DIRECTORY Include/Reai DESTINATION include)
30 changes: 20 additions & 10 deletions Include/Reai/Api/Reai.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,27 @@ extern "C" {
typedef struct Reai Reai; /* opaque object */
typedef struct ReaiResponse ReaiResponse;
typedef struct ReaiRequest ReaiRequest;
typedef struct ReaiDb ReaiDb;
typedef struct ReaiLog ReaiLog;

Reai* reai_create (CString host, CString api_key, CString model);
Reai* reai_create (CString host, CString api_key);
Reai* reai_set_mock_handler (
Reai* reai,
ReaiResponse* (*mock_handler) (
Reai* reai,
ReaiRequest* req,
ReaiResponse* response,
CString endpoint,
Uint32* http_code
)
);
void reai_destroy (Reai* reai);
ReaiResponse* reai_request (Reai* reai, ReaiRequest* req, ReaiResponse* response);
Reai* reai_set_db (Reai* reai, ReaiDb* db);
Reai* reai_set_logger (Reai* reai, ReaiLog* logger);
Reai* reai_update_all_analyses_status_in_db (Reai* reai);

CString reai_upload_file (Reai* reai, ReaiResponse* response, CString file_path);
Bool reai_auth_check (Reai* reai, ReaiResponse* response, CString host, CString api_key);
CString reai_upload_file (Reai* reai, ReaiResponse* response, CString file_path);
ReaiBinaryId reai_create_analysis (
Reai* reai,
ReaiResponse* response,
ReaiModel model,
CString ai_model,
Uint64 base_addr,
ReaiFnInfoVec* fn_info_vec,
Bool is_private,
Expand Down Expand Up @@ -77,7 +83,8 @@ extern "C" {
ReaiBinaryId bin_id,
Size max_results_per_function,
Float64 max_distance,
CStrVec* collection
CStrVec* collection,
Bool debug_mode
);

ReaiAnnFnMatchVec* reai_batch_function_symbol_ann (
Expand All @@ -87,9 +94,12 @@ extern "C" {
U64Vec* speculative_fn_ids,
Size max_results_per_function,
Float64 max_distance,
CStrVec* collection
CStrVec* collection,
Bool debug_mode
);

CStrVec* reai_get_available_models (Reai* reai, ReaiResponse* response);

#ifdef __cplusplus
}
#endif
Expand Down
31 changes: 16 additions & 15 deletions Include/Reai/Api/Request.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <Reai/Common.h>
#include <Reai/FnInfo.h>
#include <Reai/Types.h>
#include <Reai/Util/CStrVec.h>
#include <Reai/Util/IntVec.h>

#ifdef __cplusplus
Expand Down Expand Up @@ -53,7 +54,7 @@ extern "C" {
REAI_REQUEST_TYPE_UPLOAD_FILE,
/* REAI_REQUEST_TYPE_GET_CONFIG, */
REAI_REQUEST_TYPE_SEARCH,
/* REAI_REQUEST_TYPE_GET_MODELS, */
REAI_REQUEST_TYPE_GET_MODELS,

/* analysis api */
REAI_REQUEST_TYPE_CREATE_ANALYSIS,
Expand All @@ -72,22 +73,13 @@ extern "C" {
REAI_REQUEST_TYPE_BATCH_BINARY_SYMBOL_ANN,
REAI_REQUEST_TYPE_BATCH_FUNCTION_SYMBOL_ANN,

/* ai decompilation */
REAI_REQUEST_TYPE_BEGIN_AI_DECOMPILATION,
REAI_REQUEST_TYPE_POLL_AI_DECOMPILATION,

REAI_REQUEST_TYPE_MAX /**< Total number of request types */
} ReaiRequestType;

/**
* @b Represents the BinNet model to use in RevEngAI created analysis.
* This is used in create analysis request type.
* */
typedef enum ReaiModel {
REAI_MODEL_UNKNOWN = 0,
REAI_MODEL_X86_WINDOWS,
REAI_MODEL_X86_LINUX,
REAI_MODEL_X86_MACOS,
REAI_MODEL_X86_ANDROID,
REAI_MODEL_MAX
} ReaiModel;

/**
* @b Structure to be prepared with valid field values before making request to API
* endpoint.
Expand All @@ -96,12 +88,17 @@ extern "C" {
ReaiRequestType type; /**< @b Type of request. */

union {
struct {
CString host;
CString api_key;
} auth_check;

struct {
CString file_path; /**< @b Complete file path to be uploaded */
} upload_file;

struct {
ReaiModel model; /**< @b BinNet model to be used */
CString ai_model; /**< @b BinNet model to be used */
CString platform_opt; /**< @b Idk the possible values of this enum. */
CString isa_opt; /**< @b Idk possible values of this one as well. */
ReaiFileOption file_opt; /**< @b Info about file type. */
Expand Down Expand Up @@ -168,6 +165,10 @@ extern "C" {
ReaiFunctionId* speculative_function_ids;
Size speculative_function_id_count;
} batch_function_symbol_ann;

struct {
ReaiFunctionId function_id;
} begin_ai_decompilation, poll_ai_decompilation;
};
} ReaiRequest;

Expand Down
37 changes: 34 additions & 3 deletions Include/Reai/Api/Response.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <Reai/AnalysisInfo.h>
#include <Reai/AnnFnMatch.h>
#include <Reai/Api/Request.h>
#include <Reai/ApiError.h>
#include <Reai/FnInfo.h>
#include <Reai/QueryResult.h>

Expand All @@ -33,8 +34,8 @@ extern "C" {
/* utility api */
REAI_RESPONSE_TYPE_UPLOAD_FILE = REAI_REQUEST_TYPE_UPLOAD_FILE,
/* REAI_RESPONSE_TYPE_GET_CONFIG = REAI_REQUEST_TYPE_GET_CONFIG, */
REAI_RESPONSE_TYPE_SEARCH = REAI_REQUEST_TYPE_SEARCH,
/* REAI_RESPONSE_TYPE_GET_MODELS = REAI_REQUEST_TYPE_GET_MODELS, */
REAI_RESPONSE_TYPE_SEARCH = REAI_REQUEST_TYPE_SEARCH,
REAI_RESPONSE_TYPE_GET_MODELS = REAI_REQUEST_TYPE_GET_MODELS,

/* analysis api */
REAI_RESPONSE_TYPE_CREATE_ANALYSIS = REAI_REQUEST_TYPE_CREATE_ANALYSIS,
Expand All @@ -53,6 +54,10 @@ extern "C" {
REAI_RESPONSE_TYPE_BATCH_BINARY_SYMBOL_ANN = REAI_REQUEST_TYPE_BATCH_BINARY_SYMBOL_ANN,
REAI_RESPONSE_TYPE_BATCH_FUNCTION_SYMBOL_ANN = REAI_REQUEST_TYPE_BATCH_FUNCTION_SYMBOL_ANN,

/* ai decompilation */
REAI_RESPONSE_TYPE_BEGIN_AI_DECOMPILATION = REAI_REQUEST_TYPE_BEGIN_AI_DECOMPILATION,
REAI_RESPONSE_TYPE_POLL_AI_DECOMPILATION = REAI_REQUEST_TYPE_POLL_AI_DECOMPILATION,

REAI_RESPONSE_TYPE_VALIDATION_ERR,
REAI_RESPONSE_TYPE_MAX, /* enum value less than this is valid */
} ReaiResponseType;
Expand Down Expand Up @@ -108,7 +113,11 @@ extern "C" {
struct {
Bool success; /**< @b Is true when request was successful */
CString message; /**< @b Message returned by request */
} health_check, auth_check, delete_analysis;
} health_check, delete_analysis;

struct {
CString message;
} auth_check;

struct {
Bool success; /**< @b Is true when request was successful */
Expand Down Expand Up @@ -157,6 +166,28 @@ extern "C" {
} settings;
ReaiAnnFnMatchVec* function_matches;
} batch_binary_symbol_ann, batch_function_symbol_ann;

struct {
Bool success;
CStrVec* models;
} get_models;

struct {
Bool status;
CString message;
ReaiApiErrors* errors;
} begin_ai_decompilation;

struct {
Bool status;
struct {
CString status;
CString decompilation;
// TODO: function mapping?
} data;
CString message;
ReaiApiErrors* errors;
} poll_ai_decompilation;
};
} ReaiResponse;

Expand Down
30 changes: 30 additions & 0 deletions Include/Reai/ApiError.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @file ApiError.h
* @date 5th Dec 2024
* @author Siddharth Mishra ([email protected])
* @copyright Copyright (c) RevEngAI. All Rights Reserved.
* */

#ifndef REAI_API_ERROR_H
#define REAI_API_ERROR_H

#include <Reai/Types.h>
#include <Reai/Util/Vec.h>

typedef struct {
CString code;
CString message;
} ReaiApiError;

ReaiApiError* reai_api_error_clone_init (ReaiApiError* dst, ReaiApiError* src);
ReaiApiError* reai_api_error_clone_deinit (ReaiApiError* clone);

REAI_MAKE_VEC (
ReaiApiErrors,
api_error,
ReaiApiError,
reai_api_error_clone_init,
reai_api_error_vec_init
);

#endif // REAI_API_ERROR_H
Loading

0 comments on commit 3412096

Please sign in to comment.