
trailmark v0.5.0
بناء والاستعلام عن تمثيل قاعدة بيانات رسومية لشفرة المصدر
Trailmark
قم بتحليل شيفرة المصدر إلى رسوم بيانية قابلة للاستعلام عن الوظائف والكلاسات والاستدعاءات والتعليقات الدلالية لتحليل الأمان.
يستخدم Trailmark tree-sitter لتحليل AST غير مقيد بلغة معينة و rustworkx لاجتياز الرسوم البيانية عالي الأداء. الرؤية طويلة المدى هي دمج هذا الرسم البياني مع اختبار التحوير والتوجيه بالتغطية للعثور على الفجوات بين الافتراضات وتغطية الاختبار التي يمكن الوصول إليها من مدخلات المستخدم.
كيف يعمل
يعمل Trailmark في ثلاث مراحل: 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. التحليل
يقوم المحلل اللغوي المخصص بلغة معينة بجولة في الدليل، ويحلل كل ملف إلى شجرة AST من نوع tree-sitter، ويستخرج:
- **العُقد** — الدوال، الطرق، الصنوف، الهياكل، الواجهات، السمات، التعدادات، الوحدات، النطاقات
- **الحواف** — الاستدعاءات، الوراثة، التنفيذ، الاحتواء، الاستيرادات
- **البيانات الوصفية** — التعليقات التوضيحية للنوع، التعقيد الدوري، الفروع، نصوص التوثيق، أنواع الاستثناءات
### اللغات المدعومة
| اللغة | الامتدادات | البنى الرئيسية |
| --- | --- | --- |
| 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` | الدوال، الهياكل، السمات، التعدادات، كتل التنفيذ |
| Solidity | `.sol` | العقود، الواجهات، المكتبات، الدوال، المعدلات، الهياكل، التعدادات |
| Cairo | `.cairo` | الدوال، السمات، الهياكل، التعدادات، كتل التنفيذ، عقود 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، الهياكل، طرق التنفيذ، الدوال |
| Rego | `.rego` | الحزم، الاستيرادات، قواعد السياسة، استدعاءات القاعدة |
| Proto | `.proto` | الخدمات، استدعاءات الإجراءات عن بُعد (RPCs)، الرسائل، الحقول، التعدادات |
| 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
تتبع معرفات العقد النمط module:function أو module:Class أو module:Class.method للبحث غير الملتبس. يقوم تحليل الدليل بحل استدعاءات عبر الملفات البسيطة عندما يوجد تعريف فريد؛ أما الاستدعاءات عبر الملفات الغامضة فتترك عند هدفها الأصلي بأفضل جهد وتُوسم بـ uncertain. توسم ثقة الحافة بأنها certain (استدعاءات مباشرة، self.method()) أو inferred (الوصول إلى السمات على كائنات غير self) أو uncertain (التوزيع الديناميكي أو الحل الغامض).
2. الفهرس
يقوم GraphStore بتحميل CodeGraph في PyDiGraph من rustworkx ويبني تعيينات ثنائية الاتجاه للمعرفات/الفهارس للتنقل السريع.
3. الاستعلام
يوفر QueryEngine واجهة برمجة تطبيقات عالية المستوى فوق الرسم البياني المفهرس:
| Method | Description |
|---|---|
callers_of(name) | المستدعون المباشرون للهدف المسمى |
callees_of(name) | المستدعى المباشر من المصدر المسمى |
ancestors_of(name) | كل دالة يمكنها الوصول إلى الهدف بشكل متعدي (شريحة لأعلى) |
reachable_from(name) | كل دالة يمكن الوصول إليها بشكل متعدي من المصدر |
paths_between(src, dst) | كل مسارات الاستدعاء البسيطة بين عقدتين |
connect_subgraphs(source, target) | المسارات التي تربط بين رسمين بيانيين فرعيين مسمى |
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) | الحصول على تعليقات لعقدة، مرشحة حسب النوع اختيارياً |
nodes_with_annotation(kind) | كل عقدة موسومة بنوع التعليق المعطى |
clear_annotations(name, kind=None) | إزالة التعليقات من عقدة |
diff_against(other) | الفرق الهيكلي بين رسم هذا المحرك وآخر |
preanalysis() | تشغيل تمريرات التحليل المسبق المضمنة وتخزين التعليقات/الرسومات الفرعية |
augment_sarif(path) | دمج نتائج SARIF في الرسم البياني |
augment_weaudit(path) | دمج نتائج weAudit في الرسم البياني |
augment_binary(path) | دمج ملف JSON لتحليل ثنائي خارجي |
findings(kind=None) | إرجاع العقد التي تحمل تعليقات من نوع النتائج |
subgraph(name) | إرجاع العقد في رسم فرعي مسمى |
subgraph_edges(name) | إرجاع الحواف المستحثة داخل رسم فرعي مسمى |
subgraph_names() | سرد كل رسم فرعي مسمى موجود حالياً على الرسم البياني |
summary() | عدد العقد، عدد الحواف، التبعيات |
to_json() | تصدير كامل للرسم البياني |
نموذج البيانات```mermaid
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
**أنواع العُقد:** `function`, `method`, `class`, `module`, `struct`, `interface`, `trait`, `enum`, `namespace`, `contract`, `library`, `template`, `proxy`
**أصول العُقد:** `source`, `proxy`, `binary`, `synthetic`
**أنواع الحواف:** `calls`, `inherits`, `implements`, `contains`, `imports`, `resolves_to`, `type_uses`, `specializes`, `corresponds_to`
**ثقة الحافة:** `certain`, `inferred`, `uncertain`
يتم تجسيد الاستدعاءات غير المحلولة كعُقد وكيلة مثل
`proxy.unresolved:<raw-symbol>` بحيث يمكن لنتائج الاجتياز إظهار مكان فقدان التحليل المصدر للدقة بدلاً من إسقاط تلك الحافة بصمت. يدعم التحليل الثنائي استيراد رسوم بيانية للاستدعاءات بتنسيق JSON من مصادر خارجية؛ لا يقوم Trailmark بتفكيك الملفات التنفيذية بنفسه.
### مثال على رسم بياني
بإعطاء كود بايثون التالي:```python
class Auth:
def verify(self, token: str) -> bool:
return self._check_sig(token)
def _check_sig(self, token: str) -> bool:
...
def handle_request(req: Request) -> Response:
auth = Auth()
if auth.verify(req.token):
return process(req)
return deny()
Trailmark ينتج رسمًا بيانيًا مثل:```mermaid graph TD HR["handle_request"] -->|calls| AV["Auth.verify"] HR -->|calls| P["process"] HR -->|calls| D["deny"] AV -->|calls| CS["Auth._check_sig"] A["Auth"] -->|contains| AV A -->|contains| CS
classDef fn fill:#007bff26,stroke:#007bff,color:#007bff
classDef cls fill:#6f42c126,stroke:#6f42c1,color:#6f42c1
class HR,P,D fn
class A,AV,CS cls
## التثبيت
الأمثلة أدناه تتبع فرع التطوير الحالي. للحصول على أحدث حزمة منشورة، قم بالتثبيت من PyPI. للحصول على مجموعة الميزات الدقيقة الموضحة هنا، قم بالتثبيت من checkout وتشغيل الأوامر عبر `uv run`.```bash
# Latest published release
uv pip install trailmark
# Current checkout / development branch
uv sync --all-groups
يتطلب Python ≥ 3.12.
يستخدم Trailmark حزمة tree-sitter-language-pack لمعظم القواعد النحوية. تستخدم الإصدارات الحالية مخزن الشهادات الخاص بالمنصة لتنزيل القواعد النحوية. في بيئات التفتيش على TLS أو البيئات غير المتصلة، قم بتعبئة ذاكرة التخزين المؤقت للحزم مسبقًا باستخدام python -c "import tree_sitter_language_pack as p; p.download_all()" على منصة متطابقة، ثم انسخ دليل ذاكرة التخزين المؤقت tree-sitter-language-pack الناتج إلى الجهاز الهدف. يتم أيضًا احترام الـ HTTPS_PROXY. يتم شحن القاعدة النحوية لـ SQL كاعتماد لعجلة tree-sitter-sql ولا تستخدم تلك الذاكرة المؤقتة.
Usage```bash
Report the installed version
trailmark --version # or: trailmark -V trailmark version # subcommand form
Full JSON graph (Python, the default)
trailmark analyze path/to/project
Analyze a different language
trailmark analyze --language rust path/to/project trailmark analyze --language javascript path/to/project
Polyglot: auto-detect and merge every supported language found in the
tree, or pass an explicit comma-separated list.
trailmark analyze --language auto path/to/project trailmark analyze --language python,rust,solidity path/to/project
Summary statistics
trailmark analyze --summary path/to/project
Complexity hotspots (threshold >= 10)
trailmark analyze --complexity 10 path/to/project
Augment the graph with external findings (SARIF from static analyzers,
weAudit findings from the VS Code extension). Each --sarif / --weaudit
flag is repeatable. Add --json to print the augmented graph.
trailmark augment --sarif results.sarif path/to/project trailmark augment --weaudit findings.json path/to/project trailmark augment --sarif a.sarif --sarif b.sarif --json path/to/project
List detected entrypoints (attack surface). Uses heuristic detection
(main() functions, pyproject.toml [project.scripts]) plus an optional
override file at .trailmark/entrypoints.toml (see below).
trailmark entrypoints path/to/project trailmark entrypoints --json path/to/project
Structural diff between two code graphs. Accepts directory paths or
git refs (branches, tags, commits). Surfaces added/removed nodes,
call-edge changes, and — most usefully — attack-surface changes.
trailmark diff before/ after/ trailmark diff --repo . main HEAD # compare git refs trailmark diff --json before/ after/ # machine-readable output
Generate a Mermaid diagram from the code graph. --type is required; the
choices are call-graph, class-hierarchy, module-deps, containment,
complexity, and data-flow. Use --focus to scope large graphs.
trailmark diagram --target path/to/project --type call-graph trailmark diagram -t path/to/project -T call-graph -f parse_file --depth 3 trailmark diagram -t path/to/project -T complexity --threshold 5 --direction LR
### Entrypoint detection
يقوم Trailmark تلقائيًا بتعبئة `graph.entrypoints` بحيث يكون لدى `attack_surface()` وانتشار التلوث وعبور حدود الامتيازات بيانات للعمل بها. يتم الكشف في أربع طبقات، كل منها يتجاوز السابقة:
1. **الاستدلال العام `main`.** أي دالة مسماة `main` في أي لغة. موسومة `user_input` / `trusted_internal` / `low`.
2. **فحص واعي بالإطار.** أنماط الديكورات والسمات والرؤية حسب اللغة — انظر الجدول أدناه.
3. **`pyproject.toml [project.scripts]`.** تحصل أهداف CLI الصريحة على تصنيف ثقة/أصل مُرقى.
4. **ملف التجاوز المحلي للمستودع.** نقاط الدخول المُدارة يدويًا في `.trailmark/entrypoints.toml` تفوز دائمًا.
Framework coverage:
| اللغة | الأطر المكتشفة |
| --- | --- |
| Python | Flask, FastAPI, aiohttp, Click, Typer, Celery |
| JavaScript / TypeScript | NestJS, Next.js (App Router + Pages API), AWS Lambda |
| Java | Spring MVC / WebFlux, JAX-RS, Kafka listeners, servlets |
| C# | ASP.NET Core, Azure Functions |
| PHP | Symfony `#[Route]` attributes + legacy annotations |
| Rust | actix-web, rocket, FFI exports (`#[no_mangle]`, `pub extern "C"`), async-main attributes |
| Solidity | `external` / `public` visibility |
| Cairo / StarkNet | `#[external]`, `#[view]`, `#[l1_handler]`, `#[constructor]` |
| Circom | `component main` declarations |
| Miden Assembly | `export.<name>` directives |
| Haskell | top-level `main ::` / `main =` |
| Erlang | functions listed in `-export([...])` |
| Swift | `@main` app attribute |
| Objective-C | `UIApplicationDelegate` lifecycle selectors (e.g. `application:openURL:options:`) |
| Kotlin | Spring MVC / WebFlux annotations (shared with Java), Android component lifecycle methods (`onCreate`, `onReceive`, `onBind`, ...) |
| Dart | `@pragma('vm:entry-point')` native-callable markers |
| Go | `http.HandleFunc` / `http.Handle` stdlib registrations, gin/chi/echo-style `<router>.GET/POST/...` handler registrations |
| Ruby | Rails controller actions (classes inheriting `ApplicationController` / `ActionController::*`), Sidekiq worker `perform` methods |
| C / C++ | `extern "C"` linkage, `__attribute__((visibility("default")))`, `__declspec(dllexport)` |
بالنسبة لأي شيء تفوته الاستدلالات، قم بتعريف نقاط الدخول بشكل صريح في `.trailmark/entrypoints.toml` في جذر المشروع. يدعم الملف كلاً من الإدخالات أحادية العقدة والقائمة على القواعد:```toml
# Single-node entry
[[entrypoint]]
node = "my_module:handle_request" # node id, or "module.path:function"
kind = "api" # user_input | api | database | file_system | third_party
trust = "untrusted_external" # untrusted_external | semi_trusted_external | trusted_internal
asset_value = "high" # high | medium | low
description = "HTTP POST /auth"
# Rule: every PHP script under public_html/ is a web-exposed entrypoint.
[[entrypoint]]
file_glob = "public_html/**/*.php"
kind = "user_input"
trust = "untrusted_external"
asset_value = "high"
description = "Web-exposed PHP script"
# Rule: any function that takes a PSR-7 request object.
[[entrypoint]]
param_type = "ServerRequestInterface"
kind = "api"
trust = "untrusted_external"
asset_value = "high"
description = "PSR-7 HTTP handler"
# Rule: functions named `handle_*`.
[[entrypoint]]
name_regex = "^handle_"
kind = "api"
trust = "untrusted_external"
# Rule: conditions compose with AND — web.py files AND name starts with handle_.
[[entrypoint]]
file_glob = "public/*.py"
name_regex = "^handle_"
kind = "api"
trust = "untrusted_external"
الإدخالات اللاحقة تتجاوز الإدخالات السابقة عندما تضع قاعدتان علامة على نفس العقدة، لذا ضع القواعد العامة أولاً والتصحيحات المحددة بعد ذلك.
انظر docs/entrypoint-patterns.md للحصول على المرجع الكامل، بما في ذلك الأطر التي لم يتم تنفيذها بعد (Express / Koa / Fastify، Laravel، Cobra، axum، warp، clap، وغيرها) مع أنماط جاهزة للـ grep يمكن للمساهمين استخدامها لإضافة كاشفات جديدة.
الكشف عن Solidity يستخدم بيانات وصف المحلل اللغوي بدلاً من تعبيرات regex الخاصة بالتوقيع. يتم استبعاد إعلانات الواجهات وتقوم وظيفة تجاوز مشتقة بإلغاء تنفيذ القاعدة الأساسية المطابقة. تبقى الوظائف الملموسة public و external نقاط دخول، بما في ذلك وظائف view و pure؛ يتم إرجاع سماتها solidity_visibility و solidity_mutability بواسطة attack_surface() حتى يتمكن المتصلون من تمييز التعرض للقراءة فقط. تتضمن attack_surface() سمات نقطة الدخول الخاصة بالمحلل اللغوي عندما تكون مرتبطة بعقدة الرسم البياني الأساسية.
روابط عبر اللغات وخارجية
يدمج التحليل متعدد اللغات رسومًا بيانية للغات، ولكن العديد من علاقات RPC و FFI والعملية الفرعية والمضيف/العقد غير مرئية في بناء جملة المصدر. قم بتعريف هذه بشكل حتمي في .trailmark/links.toml:```toml
[[link]]
source = "backend:submit"
target = "contract:Verifier.verify"
kind = "calls" # defaults to calls
confidence = "certain" # defaults to inferred
description = "JSON-RPC eth_call"
[[link]] source = "backend:notify" target = "payments-webhook" external = true # required when either endpoint is unresolved
قد تكون المراجع معرفات عقدة دقيقة أو أسماء/لواحق فريدة. المراجع الغامضة،
نقاط النهاية الداخلية غير المعروفة، قيم التعداد غير الصالحة، و TOML غير الصحيح يثير
`ValueError`. يتيح تعيين `external = true` صراحةً نقاط النهاية غير المحلولة
ويُنشئ عقد وكيل. هذا الملف هو واجهة تكوين عامة مستقرة.
### قيود التحليل
- `entrypoint_paths_to()` يبلغ عن إمكانية الوصول عبر رسم بياني للاستدعاءات، وليس تدفق بيانات
يتحكم به المهاجم. استخدم نتائج التلوث من التحليل المسبق كإشارة منفصلة تقريبية؛ Trailmark
لا يقوم بعد بتحليل التلوث عبر الإجراءات.
- TypeScript يحل الاستدعاءات المباشرة والمستقبلات المباشرة المعينة بـ
`new ConcreteClass()`. توزيع الواجهة من خلال المانيفستات، أسماء الخصائص المحسوبة،
حاويات حقن التبعية، والآليات الديناميكية الأخرى يظل بأفضل جهد.
- دعم SQL موجه نحو PostgreSQL ويستخرج المخططات، الجداول، العروض،
الدوال، الإجراءات، وتبعيات الروتين/العرض. إنه ليس مدققًا كاملاً لصيغة SQL
أو محلل دلالات استعلام.
### واجهة برمجة التطبيقات البرمجية```python
from trailmark.parse import parse_directory, parse_file
from trailmark.query.api import QueryEngine
# Parse-only API: get the raw CodeGraph without building GraphStore/QueryEngine.
graph = parse_file("path/to/file.py")
graph = parse_directory("path/to/project", language="auto")
# Single-language (default) or auto-detect + merge across all languages
engine = QueryEngine.from_directory("path/to/project")
engine = QueryEngine.from_directory("path/to/project", language="auto")
engine = QueryEngine.from_directory("path/to/project", language="python,rust")
# Direct neighbors
engine.callers_of("handle_request")
engine.callees_of("handle_request")
# Transitive slicing — who could reach this sink, or what could it reach?
engine.ancestors_of("Auth._check_sig")
engine.reachable_from("handle_request")
# Attack-surface paths from any detected entrypoint
engine.entrypoint_paths_to("Auth._check_sig")
# All call paths between two nodes
engine.paths_between("handle_request", "Auth._check_sig")
# Functions with cyclomatic complexity >= 10
engine.complexity_hotspots(10)
# What functions can raise a given exception? (uses parser-detected
# exception_types; no runtime tracing required)
engine.functions_that_raise("PermissionError")
# Add and query semantic annotations
from trailmark.models.annotations import AnnotationKind
engine.annotate(
"handle_request",
AnnotationKind.ASSUMPTION,
"Caller has already authenticated the session token",
source="llm",
)
engine.annotations_of("handle_request")
engine.nodes_with_annotation(AnnotationKind.FINDING)
# Diff against an earlier snapshot of the same codebase
before = QueryEngine.from_directory("before/")
diff = engine.diff_against(before)
# diff contains: summary_delta, nodes {added/removed/modified},
# edges {added/removed}, entrypoints {added/removed/modified}
# Run the built-in audit-oriented preanalysis passes
engine.preanalysis()
engine.findings()
engine.subgraph_names()
# Programmatic augmentation hooks for external tooling
engine.augment_sarif("results.sarif")
engine.augment_weaudit("findings.json")
NodeKind.SCHEMA, TABLE, VIEW, و PROCEDURE مضافة في الإصدار v0.5.0؛
يجب على المستهلكين الذين يطابقون قيم التعداد بشكل شامل إضافة حالات لها.
التطوير```bash
Install package and dev dependencies
uv sync --all-groups
Lint and format
uv run ruff check --fix uv run ruff format
Type check
uv tool install ty && ty check
Tests
uv run pytest -q tests/
Mutation testing (on macOS, set this env var to avoid rustworkx fork segfaults)
OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES uv run mutmut run
## الترخيص
Apache-2.0