ソースコードをパースし、関数、クラス、呼び出し、およびセキュリティ分析のための意味注釈からなる、クエリ可能なグラフに変換します。
Trailmarkは、言語に依存しないASTパーシングにtree-sitterを、高性能グラフトラバーサルにrustworkxを使用しています。長期的なビジョンは、このグラフをミューテーションテストやカバレッジガイドファジングと組み合わせ、前提とユーザー入力から到達可能なテストカバレッジの間にあるギャップを特定することです。
Trailmark は3つのフェーズで動作します: parse、index、query。```mermaid 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
### 1. 解析
言語固有のパーサーがディレクトリを走査し、各ファイルを tree-sitter AST に解析し、以下を抽出します:
- **ノード** — 関数、メソッド、クラス、構造体、インターフェース、トレイト、列挙型、モジュール、名前空間
- **エッジ** — 呼び出し、継承、実装、包含、インポート
- **メタデータ** — 型注釈、循環的複雑度、ブランチ、ドキュメンテーション文字列、例外型
### サポートされる言語
| 言語 | 拡張子 | 主要な構成要素 |
| --- | --- | --- |
| Python | `.py` | 関数、クラス、メソッド |
| JavaScript | `.js`, `.jsx`, `.mjs`, `.cjs` | 関数、クラス、アロー関数 |
| TypeScript | `.ts`, `.tsx` | 関数、クラス、インターフェース、列挙型 |
| PHP | `.php` | 関数、クラス、インターフェース、トレイト |
| Ruby | `.rb` | メソッド、クラス、モジュール |
| C | `.c`, `.h` | 関数、構造体、列挙型 |
| C++ | `.cpp`, `.hpp`, `.cc`, `.hh`, `.cxx`, `.hxx` | 関数、クラス、構造体、名前空間 |
| C# | `.cs` | メソッド、クラス、インターフェース、構造体、列挙型、名前空間 |
| Java | `.java` | メソッド、クラス、インターフェース、列挙型 |
| Go | `.go` | 関数、メソッド、構造体、インターフェース |
| Rust | `.rs` | 関数、構造体、トレイト、列挙型、impl ブロック |
| Solidity | `.sol` | コントラクト、インターフェース、ライブラリ、関数、修飾子、構造体、列挙型 |
| Cairo | `.cairo` | 関数、トレイト、構造体、列挙型、impl ブロック、StarkNet コントラクト |
| Circom | `.circom` | テンプレート、関数、シグナル、コンポーネント |
| Haskell | `.hs` | 関数、データ型、型クラス、インスタンス |
| Erlang | `.erl` | 関数、レコード、ビヘイビア、モジュール |
| Miden Assembly | `.masm` | プロシージャ、エントリポイント、定数、呼び出し |
| Swift | `.swift` | 関数、クラス、構造体、列挙型、プロトコル、拡張 |
| Objective-C | `.m`, `.mm`, `.h` | C 関数、クラス、メソッド (セレクタベースの命名) |
| Kotlin | `.kt`, `.kts` | 関数、クラス、インターフェース、データクラス、オブジェクト、メソッド |
| Dart | `.dart` | 関数、クラス、抽象クラス、メソッド、コンストラクタ |
| Move | `.move` | モジュール、関数、インポート、直接呼び出し |
| Tact | `.tact` | コントラクト、構造体、レシーバ、関数 |
| Func | `.fc`, `.func` | 関数、インクルード、直接呼び出し |
| Sway | `.sw` | ABI インターフェース、構造体、impl メソッド、関数 |
| Rego | `.rego` | パッケージ、インポート、ポリシールール、ルール呼び出し |
| Proto | `.proto` | サービス、RPC、メッセージ、フィールド、列挙型 |
| Thrift | `.thrift` | サービス、関数、構造体、フィールド、列挙型 |
| GraphQL | `.graphql`, `.gql` | オブジェクト型、ルート操作、フィールド、列挙型 |
| SQL | `.sql` | スキーマ、テーブル、ビュー、関数、プロシージャ |```mermaid
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
ノードIDは、一意なルックアップのために module:function、module:Class、または module:Class.method のスキームに従います。ディレクトリ解析では、一意の定義が存在する場合にベアのファイル間呼び出しを解決します。曖昧なファイル間呼び出しは、元のベストエフォートのターゲットのままにされ、uncertain とマークされます。エッジの信頼性は、certain(直接呼び出し、self.method())、inferred(self以外のオブジェクトに対する属性アクセス)、または uncertain(動的ディスパッチまたは曖昧な解決)としてタグ付けされます。
GraphStore は CodeGraph を rustworkx の PyDiGraph に読み込み、高速なトラバーサルのための双方向の ID/インデックスマッピングを構築します。
QueryEngine はインデックス化されたグラフに対する高レベルAPIを提供します:
| メソッド | 説明 |
|---|---|
callers_of(name) | 指定されたターゲットの直接呼び出し元 |
callees_of(name) | 指定されたソースの直接呼び出し先 |
ancestors_of(name) | 推移的にターゲットに到達可能なすべての関数(アップワードスライス) |
reachable_from(name) | ソースから推移的に到達可能なすべての関数 |
paths_between(src, dst) | 2つのノード間のすべての単純な呼び出しパス |
connect_subgraphs(source, target) | 2つの名前付きサブグラフを接続するパス |
entrypoint_paths_to(name) | 検出された任意のエントリポイントからターゲットへのパス |
attack_surface() | 信頼レベル、アセット価値、パーサー属性が存在する場合にタグ付けされたエントリポイント |
complexity_hotspots(n) | 循環的複雑度が ≥ n の関数 |
functions_that_raise(exc) | パーサーが検出した例外リストに exc を含む関数 |
generic_parameters(name) | ノードが宣言するジェネリック型パラメータ |
type_references(name) | パラメータ、戻り値、例外、ジェネリック境界の型参照 |
annotate(name, kind, description, source) | ノードにセマンティックアノテーションを追加 |
annotations_of(name, kind=None) | ノードのアノテーションを取得。kind でフィルタリング可能 |
nodes_with_annotation(kind) | 指定されたアノテーションの種類でタグ付けされたすべてのノード |
clear_annotations(name, kind=None) | ノードからアノテーションを削除 |
diff_against(other) | このエンジンのグラフと別のグラフの構造的差分 |
preanalysis() | 組み込みの事前解析パスを実行し、アノテーション/サブグラフを保存 |
augment_sarif(path) | SARIF の findings をグラフにマージ |
augment_weaudit(path) | weAudit の findings をグラフにマージ |
augment_binary(path) | 外部のバイナリ解析グラフ JSON ファイルをマージ |
findings(kind=None) | ファインディング形式のアノテーションを持つノードを返す |
subgraph(name) | 名前付きサブグラフ内のノードを返す |
subgraph_edges(name) | 名前付きサブグラフ内の誘導エッジを返す |
subgraph_names() | グラフ上のすべての名前付きサブグラフをリスト |
summary() | ノード数、エッジ数、依存関係 |
to_json() | グラフの完全エクスポート |
classDiagram class CodeGraph { language: str root_path: str nodes: dict[str, CodeUnit] edges: list[CodeEdge] annotations: dict[str, list[Annotation]] entrypoints: dict[str, EntrypointTag] dependencies: list[str] add_annotation(node_id, annotation) clear_annotations(node_id, kind=None) merge(other) }
class CodeUnit {
id: str
name: str
kind: NodeKind
location: SourceLocation
parameters: tuple[Parameter]
return_type: TypeRef
exception_types: tuple[TypeRef]
cyclomatic_complexity: int
branches: tuple[BranchInfo]
docstring: str
}
class CodeEdge {
source_id: str
target_id: str
kind: EdgeKind
confidence: EdgeConfidence
}
class Annotation {
kind: AnnotationKind
description: str
source: str
}
class EntrypointTag {
kind: EntrypointKind
trust_level: TrustLevel
description: str
asset_value: AssetValue
}
CodeGraph "1" *-- "*" CodeUnit
CodeGraph "1" *-- "*" CodeEdge
CodeGraph "1" *-- "*" Annotation
CodeGraph "1" *-- "*" EntrypointTag
**Node kinds:** `function`(関数), `method`(メソッド), `class`(クラス), `module`(モジュール), `struct`(構造体), `interface`(インターフェース), `trait`(トレイト), `enum`(列挙型), `namespace`(名前空間), `contract`(コントラクト), `library`(ライブラリ), `template`(テンプレート), `proxy`(プロキシ)
**Node origins:** `source`(ソース), `proxy`(プロキシ), `binary`(バイナリ), `synthetic`(合成)
**Edge kinds:** `calls`(呼び出し), `inherits`(継承), `implements`(実装), `contains`(包含), `imports`(インポート), `resolves_to`(解決先), `type_uses`(型使用), `specializes`(特殊化), `corresponds_to`(対応)
**Edge confidence:** `certain`(確実), `inferred`(推論), `uncertain`(不確か)
未解決の呼び出しは、`proxy.unresolved:<raw-symbol>` のようなプロキシノードとして具現化され、トラバーサル結果は、ソース分析が解決を失った場所を、そのエッジを黙って落とす代わりに表示できます。バイナリ分析は外部JSONコールグラフのインポートをサポートします。Trailmarkが実行ファイルを逆アセンブルすることはありません。
### グラフ例
以下のPythonコードを例とします:```python
class Auth:
def verify(self, token: str) -> bool:
return self._check_sig(token)
def _check_sig(self, token: str) -> bool:
...