
Construire et interroger une représentation en base de données graphe du code source.
Analyse le code source en graphes interrogeables de fonctions, de classes, d'appels et d'annotations sémantiques pour l'analyse de sécurité.
Trailmark utilise tree-sitter pour l'analyse AST indépendante du langage et rustworkx pour un parcours de graphe hautes performances. La vision à long terme est de combiner ce graphe avec le mutation testing et le fuzzing guidé par la couverture afin d'identifier les écarts entre les hypothèses et la couverture de tests qui sont atteignables depuis les entrées utilisateur.
Trailmark fonctionne en trois phases : parse, index et query.
flowchart TD
A["Source Files"] --> B["tree-sitter Parser"]
B --> C["CodeGraph (nodes + edges)"]
C --> D["rustworkx GraphStore"]
D --> E["QueryEngine"]
E --> F["JSON / Summary / Hotspots"]
classDef src fill:#007bff26,stroke:#007bff,color:#007bff
classDef parse fill:#28a74526,stroke:#28a745,color:#28a745
classDef data fill:#6f42c126,stroke:#6f42c1,color:#6f42c1
classDef query fill:#ffc10726,stroke:#e6a817,color:#e6a817
class A src
class B parse
class C,D data
class E,F query
Un analyseur syntaxique spécifique à chaque langage parcourt le répertoire, analyse chaque fichier en un AST tree-sitter et extrait :
| Langage | Extensions | Constructions clés |
|---|---|---|
| Python | .py | fonctions, classes, méthodes |
| JavaScript | .js, .jsx, .mjs, .cjs | fonctions, classes, fonctions fléchées |
| TypeScript | .ts, .tsx | fonctions, classes, interfaces, énumérations |
| PHP | .php | fonctions, classes, interfaces, traits |
| Ruby | .rb | méthodes, classes, modules |
| C | .c, .h | fonctions, structures, énumérations |
| C++ | .cpp, .hpp, .cc, .hh, .cxx, .hxx | fonctions, classes, structures, espaces de noms |
| C# | .cs | méthodes, classes, interfaces, structures, énumérations, espaces de noms |
| Java | .java | méthodes, classes, interfaces, énumérations |
| Go | .go | fonctions, méthodes, structures, interfaces |
| Rust | .rs | fonctions, structures, traits, énumérations, blocs impl, blocs verus! |
| Solidity | .sol | contrats, interfaces, bibliothèques, fonctions, modificateurs, structures, énumérations |
| Cairo | .cairo | fonctions, traits, structures, énumérations, blocs impl, contrats StarkNet |
| Circom | .circom | templates, fonctions, signaux, composants |
| Haskell | .hs | fonctions, types de données, classes de types, instances |
| Erlang | .erl | fonctions, enregistrements, comportements, modules |
| Miden Assembly | .masm | procédures, points d'entrée, constantes, invocations |
| Swift | .swift | fonctions, classes, structures, énumérations, protocoles, extensions |
| Objective-C | .m, .mm, .h | fonctions C, classes, méthodes (nommage basé sur les sélecteurs) |
| Kotlin | .kt, .kts | fonctions, classes, interfaces, classes de données, objets, méthodes |
| Dart | .dart | fonctions, classes, classes abstraites, méthodes, constructeurs |
| Move | .move | modules, fonctions, imports, appels directs |
| Tact | .tact | contrats, structures, récepteurs, fonctions |
| Func | .fc, .func | fonctions, includes, appels directs |
| Sway | .sw | interfaces ABI, structures, méthodes impl, fonctions |
| Rego | .rego | paquets, imports, règles de politique, appels de règles |
| Proto | .proto | services, RPC, messages, champs, énumérations |
| Thrift | .thrift | services, fonctions, structures, champs, énumérations |
| GraphQL | .graphql, .gql | types d'objets, opérations racines, champs, énumérations |
| SQL | .sql | schémas, tables, vues, fonctions, procédures |
Le parseur Rust extrait les fonctions ordinaires, spec et proof avec leurs corps depuis les blocs verus! { ... }. La grammaire Verus ne prend actuellement en charge que les blocs délimités par des accolades ; verus!(...) et verus![...] sont ignorés avec un avertissement. Les modules inline conservent des ID qualifiés (par exemple, file.inner:function), et les méthodes conservent leur propriétaire impl ou trait. Chaque bloc est analysé indépendamment ; les erreurs de syntaxe produisent un avertissement avec le fichier et l'emplacement du bloc. Les invocations qualifiées telles que vstd::prelude::verus! sont également prises en charge. Les fonctions d'assistance locales conservent leur fonction englobante dans leurs ID (par exemple, file:outer.inner). Les appels à ces fonctions d'assistance et les imports relatifs tels que use super::* sont résolus vers les déclarations présentes dans le fichier. Les noms locaux répétés dans différents blocs reçoivent un suffixe de décalage d'octet pour garder leurs nœuds distincts, et les appels respectent la portée du bloc. Les structs, enums, traits et modules inline locaux conservent également la fonction englobante : par exemple, file:outer.Guard.drop et file:outer.local.helper. Leurs corps ont des appels et une complexité distincts. Les appels explicites vers des types et modules locaux connus sont résolus au sein du fichier. Les appels nus recherchent dans les portées des fonctions et des modules ; les éléments associés utilisent des chemins tels que Type::method. Les appels pointés ne sont résolus que lorsque le récepteur nomme un struct ou un enum connu. Les autres récepteurs de valeur, y compris self.method(), restent non résolus. Les appels implicites aux destructeurs et l'inférence de type du récepteur ne sont pas modélisés. Ces règles s'appliquent au Rust ordinaire ainsi qu'aux blocs Verus. Modifier le code avant une déclaration avec un suffixe de décalage change son ID, de sorte que trailmark diff peut signaler cette déclaration comme supprimée et ajoutée.
Trailmark ne développe pas les macros arbitraires. Les invocations Verus littérales à l'intérieur de macros opaques ou de corps de fonctions sont ignorées avec un avertissement. Les définitions macro_rules! non invoquées ne sont pas développées. Les signatures de fonctions sans corps et les appels dans les clauses requires/ensures ne sont pas extraits.
flowchart TD
subgraph "Per-File Parsing"
F["Source file"] --> TS["tree-sitter AST"]
TS --> EX["Extract nodes"]
TS --> EC["Extract call edges"]
TS --> EB["Count branches"]
TS --> ET["Resolve types"]
end
EX --> CG["CodeGraph"]
EC --> CG
EB --> CG
ET --> CG
classDef src fill:#007bff26,stroke:#007bff,color:#007bff
classDef parse fill:#28a74526,stroke:#28a745,color:#28a745
classDef extract fill:#ffc10726,stroke:#e6a817,color:#e6a817
classDef data fill:#6f42c126,stroke:#6f42c1,color:#6f42c1
class F src
class TS parse
class EX,EC,EB,ET extract
class CG data