feat(osint): sync actions with tool registry

This commit is contained in:
grayTerminal-sh 2026-07-22 11:44:31 +02:00
parent 947f9550dc
commit b1b2320469
9 changed files with 216 additions and 8 deletions

View file

@ -143,7 +143,8 @@ Le socle actuel comprend notamment :
- détection de présence et de version ;
- menu OSINT contextuel préparé pour les entités et relations du graphe ;
- contexte de sélection OSINT indépendant de GTK et validé par des tests ;
- catalogue déterministe des actions compatibles avec la sélection OSINT.
- catalogue déterministe des actions compatibles avec la sélection OSINT ;
- disponibilité des actions OSINT synchronisée avec le registre doutils.
Les outils actuellement présents dans le catalogue initial sont :

View file

@ -18,6 +18,15 @@ typedef struct OsintAction OsintAction;
/** @brief Catalogue opaque possédant ses actions. */
typedef struct OsintActionCatalog OsintActionCatalog;
/** @brief État d'une dépendance externe vu par le catalogue OSINT. */
typedef enum
{
OSINT_ACTION_TOOL_STATE_UNKNOWN,
OSINT_ACTION_TOOL_STATE_AVAILABLE,
OSINT_ACTION_TOOL_STATE_MISSING,
OSINT_ACTION_TOOL_STATE_INCOMPATIBLE
} OsintActionToolState;
/**
* @brief Crée le catalogue initial déterministe.
*
@ -48,6 +57,21 @@ GPtrArray *osint_action_catalog_list_compatible(
const OsintSelectionContext *context
);
/**
* @brief Actualise les actions dépendant d'un outil externe.
*
* @param catalog Catalogue à modifier.
* @param tool_identifier Identifiant stable de l'outil.
* @param state État traduit par la couche applicative.
* @param version Version détectée facultative.
*/
void osint_action_catalog_update_tool_state(
OsintActionCatalog *catalog,
const char *tool_identifier,
OsintActionToolState state,
const char *version
);
/** @brief Retourne l'identifiant stable emprunté d'une action. */
const char *osint_action_get_identifier(const OsintAction *action);
@ -68,6 +92,9 @@ gboolean osint_action_is_available(const OsintAction *action);
/** @brief Retourne l'explication d'indisponibilité, ou NULL. */
const char *osint_action_get_unavailable_reason(const OsintAction *action);
/** @brief Retourne la version copiée de l'outil requis, ou NULL. */
const char *osint_action_get_tool_version(const OsintAction *action);
G_END_DECLS
#endif

View file

@ -12,6 +12,7 @@
#include "core/task_manager.h"
#include "widgets/evidence_category_model.h"
#include "models/evidence_record.h"
#include "models/osint_action_catalog.h"
#include <gtk/gtk.h>
@ -403,6 +404,21 @@ void main_window_set_status(
const char *status_text
);
/**
* @brief Transmet au workspace l'état d'un outil OSINT externe.
*
* @param main_window Fenêtre principale.
* @param tool_identifier Identifiant stable de l'outil.
* @param state État traduit par l'application.
* @param version Version détectée facultative.
*/
void main_window_set_osint_tool_state(
MainWindow *main_window,
const char *tool_identifier,
OsintActionToolState state,
const char *version
);
/**
* @brief Callback appelé lorsque l'utilisateur demande l'ouverture
* d'une enquête existante.

View file

@ -8,6 +8,7 @@
#include "core/investigation_node.h"
#include "models/evidence_record.h"
#include "models/osint_action_catalog.h"
#include <gtk/gtk.h>
@ -155,6 +156,21 @@ gboolean workspace_select_graph_relation(
const char *relation_identifier
);
/**
* @brief Actualise l'état d'un outil requis par les actions OSINT.
*
* @param workspace Zone de travail.
* @param tool_identifier Identifiant stable de l'outil.
* @param state État traduit par la couche applicative.
* @param version Version détectée facultative.
*/
void workspace_set_osint_tool_state(
Workspace *workspace,
const char *tool_identifier,
OsintActionToolState state,
const char *version
);
/**
* @brief Définit le callback de vérification de la preuve affichée.
*

View file

@ -729,6 +729,42 @@ static void application_present_error(
const char *message
);
/**
* @brief Publie dans l'interface les états du registre d'outils.
*/
static void application_publish_osint_tool_states(
Application *application
)
{
ToolRegistry *tool_registry = NULL;
gsize tool_index = 0;
if (application == NULL || application->main_window == NULL ||
application->tool_initializer == NULL)
{
return;
}
tool_registry = tool_initializer_get_registry(application->tool_initializer);
for (tool_index = 0;
tool_registry != NULL && tool_index < tool_registry_get_count(tool_registry);
tool_index++)
{
const ToolInfo *tool_info = tool_registry_get_tool(tool_registry, tool_index);
OsintActionToolState state = OSINT_ACTION_TOOL_STATE_UNKNOWN;
if (tool_info_get_availability(tool_info) == TOOL_AVAILABILITY_AVAILABLE)
state = OSINT_ACTION_TOOL_STATE_AVAILABLE;
else if (tool_info_get_availability(tool_info) == TOOL_AVAILABILITY_MISSING)
state = OSINT_ACTION_TOOL_STATE_MISSING;
main_window_set_osint_tool_state(
application->main_window,
tool_info_get_identifier(tool_info),
state,
tool_info_get_detected_version(tool_info)
);
}
}
/**
* @brief Traite la fin de linitialisation des outils externes.
*
@ -828,6 +864,8 @@ static void application_on_tool_initialization_completed(
break;
}
application_publish_osint_tool_states(application);
}
/**

View file

@ -15,6 +15,7 @@ struct OsintAction
char *required_tool_identifier;
gboolean available;
char *unavailable_reason;
char *tool_version;
};
struct OsintActionCatalog
@ -28,6 +29,7 @@ static void osint_action_free(gpointer data)
OsintAction *action = data;
if (action == NULL) return;
g_free(action->unavailable_reason);
g_free(action->tool_version);
g_free(action->compatible_type);
g_free(action->required_tool_identifier);
g_free(action->description);
@ -83,8 +85,8 @@ OsintActionCatalog *osint_action_catalog_new_defaults(void)
dns_action = osint_action_new(
"dns-preview", "Résolution DNS",
"Préfiguration de l'adaptateur DNS.",
OSINT_SELECTION_CONTEXT_KIND_ENTITY, "domain", "dig", FALSE,
"L'adaptateur DNS n'est pas encore intégré."
OSINT_SELECTION_CONTEXT_KIND_ENTITY, "domain_name", "dns.dig", FALSE,
"L'outil requis n'a pas encore été vérifié."
);
if (catalog->actions == NULL || demonstration_action == NULL ||
dns_action == NULL)
@ -134,6 +136,35 @@ GPtrArray *osint_action_catalog_list_compatible(
return compatible_actions;
}
void osint_action_catalog_update_tool_state(
OsintActionCatalog *catalog,
const char *tool_identifier,
OsintActionToolState state,
const char *version
)
{
guint index = 0;
if (catalog == NULL || catalog->actions == NULL ||
tool_identifier == NULL || tool_identifier[0] == '\0') return;
for (index = 0; index < catalog->actions->len; index++)
{
OsintAction *action = g_ptr_array_index(catalog->actions, index);
if (g_strcmp0(action->required_tool_identifier, tool_identifier) != 0)
continue;
g_clear_pointer(&action->tool_version, g_free);
g_clear_pointer(&action->unavailable_reason, g_free);
action->available = state == OSINT_ACTION_TOOL_STATE_AVAILABLE;
if (action->available)
action->tool_version = g_strdup(version);
else if (state == OSINT_ACTION_TOOL_STATE_MISSING)
action->unavailable_reason = g_strdup("L'outil requis est absent.");
else if (state == OSINT_ACTION_TOOL_STATE_INCOMPATIBLE)
action->unavailable_reason = g_strdup("La version installée est incompatible.");
else
action->unavailable_reason = g_strdup("L'outil requis n'a pas encore été vérifié.");
}
}
void osint_action_catalog_free(OsintActionCatalog *catalog)
{
if (catalog == NULL) return;
@ -153,3 +184,5 @@ gboolean osint_action_is_available(const OsintAction *action)
{ return action != NULL && action->available; }
const char *osint_action_get_unavailable_reason(const OsintAction *action)
{ return action != NULL ? action->unavailable_reason : NULL; }
const char *osint_action_get_tool_version(const OsintAction *action)
{ return action != NULL ? action->tool_version : NULL; }

View file

@ -1225,6 +1225,26 @@ void main_window_set_status(
);
}
void main_window_set_osint_tool_state(
MainWindow *main_window,
const char *tool_identifier,
OsintActionToolState state,
const char *version
)
{
if (main_window == NULL)
{
return;
}
workspace_set_osint_tool_state(
main_window->workspace,
tool_identifier,
state,
version
);
}
void main_window_set_tree_selection_callback(
MainWindow *main_window,
InvestigationTreeViewSelectionCallback callback,

View file

@ -259,9 +259,13 @@ static void workspace_update_osint_tools_menu(
compatible_actions,
action_index
);
GtkWidget *action_button = gtk_button_new_with_label(
osint_action_get_label(action)
);
const char *tool_version = osint_action_get_tool_version(action);
char *button_label = tool_version != NULL && tool_version[0] != '\0'
? g_strdup_printf("%s — %s", osint_action_get_label(action), tool_version)
: g_strdup(osint_action_get_label(action));
GtkWidget *action_button = gtk_button_new_with_label(button_label);
g_free(button_label);
if (action_button == NULL)
{
@ -2324,6 +2328,30 @@ gboolean workspace_select_graph_relation(
);
}
void workspace_set_osint_tool_state(
Workspace *workspace,
const char *tool_identifier,
OsintActionToolState state,
const char *version
)
{
if (workspace == NULL || workspace->osint_action_catalog == NULL)
{
return;
}
osint_action_catalog_update_tool_state(
workspace->osint_action_catalog,
tool_identifier,
state,
version
);
workspace_update_osint_tools_menu(
workspace,
workspace->osint_selection_context
);
}
void workspace_set_graph_loading(
Workspace *workspace
)

View file

@ -18,7 +18,7 @@ static OsintSelectionContext *create_entity_context(const char *type)
static void test_domain_actions(void)
{
OsintActionCatalog *catalog = osint_action_catalog_new_defaults();
OsintSelectionContext *context = create_entity_context("domain");
OsintSelectionContext *context = create_entity_context("domain_name");
GPtrArray *actions = osint_action_catalog_list_compatible(catalog, context);
g_assert_nonnull(actions);
@ -28,7 +28,7 @@ static void test_domain_actions(void)
g_assert_true(osint_action_is_available(g_ptr_array_index(actions, 0)));
g_assert_false(osint_action_is_available(g_ptr_array_index(actions, 1)));
g_assert_cmpstr(osint_action_get_required_tool_identifier(
g_ptr_array_index(actions, 1)), ==, "dig");
g_ptr_array_index(actions, 1)), ==, "dns.dig");
g_assert_nonnull(osint_action_get_unavailable_reason(
g_ptr_array_index(actions, 1)));
@ -59,11 +59,40 @@ static void test_invalid_arguments(void)
osint_action_catalog_free(NULL);
}
static void test_tool_states(void)
{
OsintActionCatalog *catalog = osint_action_catalog_new_defaults();
OsintSelectionContext *context = create_entity_context("domain_name");
GPtrArray *actions = NULL;
osint_action_catalog_update_tool_state(
catalog, "dns.dig", OSINT_ACTION_TOOL_STATE_AVAILABLE, "DiG 9.20"
);
actions = osint_action_catalog_list_compatible(catalog, context);
g_assert_true(osint_action_is_available(g_ptr_array_index(actions, 1)));
g_assert_cmpstr(osint_action_get_tool_version(g_ptr_array_index(actions, 1)),
==, "DiG 9.20");
g_ptr_array_unref(actions);
osint_action_catalog_update_tool_state(
catalog, "dns.dig", OSINT_ACTION_TOOL_STATE_MISSING, NULL
);
actions = osint_action_catalog_list_compatible(catalog, context);
g_assert_false(osint_action_is_available(g_ptr_array_index(actions, 1)));
g_assert_nonnull(osint_action_get_unavailable_reason(
g_ptr_array_index(actions, 1)));
g_ptr_array_unref(actions);
osint_selection_context_free(context);
osint_action_catalog_free(catalog);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
g_test_add_func("/osint-action-catalog/domain", test_domain_actions);
g_test_add_func("/osint-action-catalog/non-domain", test_non_domain_actions);
g_test_add_func("/osint-action-catalog/invalid", test_invalid_arguments);
g_test_add_func("/osint-action-catalog/tool-states", test_tool_states);
return g_test_run();
}