Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

FeedsContactoPrivacidad© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
trailmark — Construye y consulta una representación de base de datos de grafos del código fuente. | Kitploit
Herramientas/GitHubGitHub/trailofbits/trailmark
Análisis EstáticoAnálisis de VulnerabilidadesAnálisis de CódigoFuzzingAnálisis de BinariosAprendizaje y Educación
GitHubtrailofbits/trailmark

trailmark

Construye y consulta una representación de base de datos de grafos del código fuente.

Ver Repositorio
4632925hace 4 díasRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
# Trailmark

[![CI](https://github.com/trailofbits/trailmark/actions/workflows/ci.yml/badge.svg)](https://github.com/trailofbits/trailmark/actions/workflows/ci.yml)
[![Mutation Testing](https://github.com/trailofbits/trailmark/actions/workflows/mutation.yml/badge.svg)](https://github.com/trailofbits/trailmark/actions/workflows/mutation.yml)

Analiza el código fuente en grafos consultables de funciones, clases, llamadas y anotaciones semánticas para el análisis de seguridad.

Trailmark utiliza [tree-sitter](https://tree-sitter.github.io/) para el análisis de AST independiente del lenguaje y [rustworkx](https://www.rustworkx.org/) para el recorrido de grafos de alto rendimiento. La visión a largo plazo es combinar este grafo con pruebas de mutación y fuzzing guiado por cobertura para identificar brechas entre las suposiciones y la cobertura de pruebas que sean alcanzables desde la entrada del usuario.

## Cómo funciona

Trailmark opera en tres fases: **parse**, **index** y **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. Análisis

Un analizador específico del lenguaje recorre el directorio, analiza cada archivo en un AST de tree-sitter y extrae:

- **Nodos** — funciones, métodos, clases, structs, interfaces, traits, enums, módulos, espacios de nombres
- **Aristas** — llamadas, herencia, implementación, contención, importaciones
- **Metadatos** — anotaciones de tipo, complejidad ciclomática, ramas, docstrings, tipos de excepción

### Lenguajes compatibles

| Lenguaje | Extensiones | Construcciones clave |
| --- | --- | --- |
| Python | `.py` | funciones, clases, métodos |
| JavaScript | `.js`, `.jsx`, `.mjs`, `.cjs` | funciones, clases, funciones flecha |
| TypeScript | `.ts`, `.tsx` | funciones, clases, interfaces, enums |
| PHP | `.php` | funciones, clases, interfaces, traits |
| Ruby | `.rb` | métodos, clases, módulos |
| C | `.c`, `.h` | funciones, structs, enums |
| C++ | `.cpp`, `.hpp`, `.cc`, `.hh`, `.cxx`, `.hxx` | funciones, clases, structs, espacios de nombres |
| C# | `.cs` | métodos, clases, interfaces, structs, enums, espacios de nombres |
| Java | `.java` | métodos, clases, interfaces, enums |
| Go | `.go` | funciones, métodos, structs, interfaces |
| Rust | `.rs` | funciones, structs, traits, enums, bloques impl, bloques `verus!` |
| Solidity | `.sol` | contratos, interfaces, librerías, funciones, modificadores, structs, enums |
| Cairo | `.cairo` | funciones, traits, structs, enums, bloques impl, contratos StarkNet |
| Circom | `.circom` | plantillas, funciones, señales, componentes |
| Haskell | `.hs` | funciones, tipos de datos, clases de tipos, instancias |
| Erlang | `.erl` | funciones, registros, comportamientos, módulos |
| Miden Assembly | `.masm` | procedimientos, puntos de entrada, constantes, invocaciones |
| Swift | `.swift` | funciones, clases, structs, enums, protocolos, extensiones |
| Objective-C | `.m`, `.mm`, `.h` | funciones C, clases, métodos (nombres basados en selectores) |
| Kotlin | `.kt`, `.kts` | funciones, clases, interfaces, clases de datos, objetos, métodos |
| Dart | `.dart` | funciones, clases, clases abstractas, métodos, constructores |
| Move | `.move` | módulos, funciones, importaciones, llamadas directas |
| Tact | `.tact` | contratos, structs, receptores, funciones |
| Func | `.fc`, `.func` | funciones, inclusiones, llamadas directas |
| Sway | `.sw` | interfaces ABI, structs, métodos impl, funciones |
| Rego | `.rego` | paquetes, importaciones, reglas de política, llamadas a reglas |
| Proto | `.proto` | servicios, RPCs, mensajes, campos, enums |
| Thrift | `.thrift` | servicios, funciones, structs, campos, enums |
| GraphQL | `.graphql`, `.gql` | tipos de objeto, operaciones raíz, campos, enums |
| SQL | `.sql` | esquemas, tablas, vistas, funciones, procedimientos |

El analizador de Rust extrae funciones ordinarias, `spec` y `proof` con cuerpos
de bloques `verus! { ... }`. La gramática de Verus actualmente solo admite
bloques delimitados por llaves; `verus!(...)` y `verus![...]` se omiten con una advertencia.
Los módulos en línea conservan IDs cualificados (por ejemplo, `file.inner:function`), y
los métodos conservan su propietario impl o trait. Cada bloque se analiza de forma independiente;
los errores de sintaxis producen una advertencia con la ubicación del archivo y del bloque.
También se admiten invocaciones cualificadas como `vstd::prelude::verus!`.
Las funciones auxiliares locales conservan su función contenedora en sus IDs (por ejemplo,
`file:outer.inner`). Las llamadas a estas funciones auxiliares y las importaciones relativas como
`use super::*` se resuelven a declaraciones presentes en el archivo.
Los nombres locales repetidos en distintos bloques reciben un sufijo de desplazamiento de bytes para mantener
sus nodos distintos, y las llamadas respetan el ámbito del bloque.
Los structs, enums, traits y módulos en línea locales también conservan la función contenedora:
por ejemplo, `file:outer.Guard.drop` y `file:outer.local.helper`.
Sus cuerpos tienen llamadas y complejidad separadas. Las llamadas explícitas a tipos y módulos
locales conocidos se resuelven dentro del archivo. Las llamadas sin cualificar buscan en los ámbitos de funciones y módulos;
los elementos asociados usan rutas como `Type::method`. Las llamadas con punto se resuelven
solo cuando el receptor nombra un struct o enum conocido. Otros receptores de valor,
incluido `self.method()`, permanecen sin resolver. Las llamadas implícitas a destructores y la inferencia
de tipos del receptor no se modelan. Estas reglas se aplican tanto al Rust ordinario como a los
bloques de Verus. Editar código antes de una declaración con un sufijo de desplazamiento cambia
su ID, por lo que `trailmark diff` puede informar esa declaración como eliminada y añadida.

Trailmark no expande macros arbitrarias. Las invocaciones literales de Verus dentro de
macros opacas o cuerpos de funciones se omiten con una advertencia. Las definiciones de
`macro_rules!` no invocadas no se expanden. Las firmas de funciones sin cuerpos
y las llamadas en cláusulas `requires`/`ensures` no se extraen.

```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
```

Los ID de nodo siguen el esquema `module:function`, `module:Class` o `module:Class.method` para una búsqueda inequívoca. El análisis de directorios resuelve las llamadas entre archivos sin calificar cuando existe una definición única; las llamadas entre archivos ambiguas se dejan en su objetivo original de mejor esfuerzo y se marcan como `uncertain`. La confianza de las aristas se etiqueta como `certain` (llamadas directas, `self.method()`), `inferred` (acceso a atributos en objetos que no son self) o `uncertain` (despacho dinámico o resolución ambigua).

### 2. Index

El `GraphStore` carga el `CodeGraph` en un `PyDiGraph` de rustworkx y construye asignaciones bidireccionales de ID/índice para un recorrido rápido.

### 3. Query

El `QueryEngine` proporciona una API de alto nivel sobre el grafo indexado:

| Método | Descripción |
| --- | --- |
| `callers_of(name)` | Llamadores directos del objetivo nombrado |
| `callees_of(name)` | Llamados directos de la fuente nombrada |
| `ancestors_of(name)` | Toda función que puede alcanzar transitivamente el objetivo (rebanada ascendente) |
| `reachable_from(name)` | Toda función alcanzable transitivamente desde la fuente |
| `paths_between(src, dst)` | Todas las rutas de llamada simples entre dos nodos |
| `connect_subgraphs(source, target)` | Rutas que conectan dos subgrafos nombrados |
| `entrypoint_paths_to(name)` | Rutas desde cualquier punto de entrada detectado hasta el objetivo |
| `attack_surface()` | Puntos de entrada etiquetados con nivel de confianza, valor del activo y atributos del analizador cuando están presentes |
| `complexity_hotspots(n)` | Funciones con complejidad ciclomática ≥ n |
| `functions_that_raise(exc)` | Funciones cuya lista de excepciones detectada por el analizador incluye `exc` |
| `generic_parameters(name)` | Parámetros de tipo genérico declarados por un nodo |
| `type_references(name)` | Referencias de tipo de parámetro, retorno, excepción y límite genérico |
| `annotate(name, kind, description, source)` | Añadir una anotación semántica a un nodo |
| `annotations_of(name, kind=None)` | Obtener las anotaciones de un nodo, opcionalmente filtradas por tipo |
| `nodes_with_annotation(kind)` | Todo nodo etiquetado con el tipo de anotación dado |
| `clear_annotations(name, kind=None)` | Eliminar anotaciones de un nodo |
| `diff_against(other)` | Diff estructural del grafo de este motor frente a otro |
| `preanalysis()` | Ejecutar las pasadas de preanálisis integradas y almacenar anotaciones/subgrafos |
| `augment_sarif(path)` | Fusionar hallazgos SARIF en el grafo |
| `augment_weaudit(path)` | Fusionar hallazgos de weAudit en el grafo |
| `augment_binary(path)` | Fusionar un archivo JSON de grafo de análisis binario externo |
| `findings(kind=None)` | Devolver los nodos que llevan anotaciones de tipo hallazgo |
| `subgraph(name)` | Devolver los nodos de un subgrafo nombrado |
| `subgraph_edges(name)` | Devolver las aristas inducidas dentro de un subgrafo nombrado |
| `subgraph_names()` | Listar todos los subgrafos nombrados actualmente en el grafo |
| `summary()` | Recuentos de nodos, recuentos de aristas, dependencias |
| `to_json()` | Exportación completa del grafo |

### Modelo de datos

```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
```

**Tipos de nodo:** `function`, `method`, `class`, `module`, `struct`, `interface`, `trait`, `enum`, `namespace`, `contract`, `library`, `template`, `proxy`

**Orígenes de nodo:** `source`, `proxy`, `binary`, `synthetic`

**Tipos de arista:** `calls`, `inherits`, `implements`, `contains`, `imports`, `resolves_to`, `type_uses`, `specializes`, `corresponds_to`

**Confianza de arista:** `certain`, `inferred`, `uncertain`

Las llamadas no resueltas se materializan como nodos proxy tales como
`proxy.unresolved:<raw-symbol>` para que los resultados de recorrido puedan mostrar dónde el análisis de código fuente perdió la resolución en lugar de descartar silenciosamente esa arista. Los análisis de directorios, incluidos los análisis de un solo lenguaje, también aplican enlaces de repositorio y materializan aristas `TYPE_USES`. El soporte de análisis binario importa grafos de llamadas JSON externos; Trailmark no desensambla ejecutables por sí mismo.

### Grafo de ejemplo

Dado este código Python:

```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 produce un grafo como:

```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
```

## Instalación

Los ejemplos a continuación siguen la rama de desarrollo actual. Para el paquete
publicado más reciente, instale desde PyPI. Para el conjunto exacto de funciones descrito
aquí, instale desde una copia local y ejecute los comandos mediante `uv run`.

```bash
# Latest published release
uv pip install trailmark

# Current checkout / development branch
uv sync --all-groups
```

Requiere Python &ge; 3.12.

Trailmark requiere `tree-sitter-language-pack` 1.22.1 o posterior para la mayoría de las gramáticas.
Las cachés de gramáticas propiedad de root son compatibles cuando no son escribibles por grupo u otros.
Las versiones actuales utilizan el almacén de certificados de la plataforma para las descargas de gramáticas. En
entornos con inspección TLS o sin conexión, prellene la caché del paquete con
`python -c "import tree_sitter_language_pack as p; p.download_all()"` en una
plataforma compatible, y luego copie el directorio de caché resultante de `tree-sitter-language-pack` a la máquina de destino. También se respeta `HTTPS_PROXY`. La gramática SQL
se distribuye como la dependencia del wheel `tree-sitter-sql` y no utiliza esa caché.

Las gramáticas incluidas Circom, Miden Assembly y Verus se compilan en el primer uso.
Esto requiere un compilador de C (`cc`), los encabezados de desarrollo de Python y acceso de escritura
a sus directorios de gramáticas instalados. Los archivos Rust sin bloques Verus no
activan la compilación. Si la gramática Verus no se puede compilar o cargar, Trailmark
registra una advertencia, omite los bloques Verus y continúa analizando Rust ordinario.
La caché de enlace de Verus incluye los contenidos del código fuente compilado, la ABI de Python,
la plataforma y las opciones del compilador. Las entradas modificadas seleccionan un nuevo enlace; las compilaciones
completadas se publican de forma atómica. Los fallos del compilador incluyen el estado de salida y
stderr en la advertencia.

Las copias de trabajo de Git conservan la definición de la gramática Verus y generan su analizador C durante
las compilaciones con Tree-sitter CLI 0.27.1. Antes de `uv sync` o `uv build` en una copia de trabajo,
ejecute `npm ci` con los scripts de instalación de npm habilitados; se necesita Node.js para la generación.
El analizador y los encabezados generados están en gitignore. Los wheels y las distribuciones de código fuente
incluyen estos códigos fuente generados, por lo que instalar los paquetes publicados no requiere ni
Node.js ni Tree-sitter CLI.
Las instalaciones editables de `uv` vuelven a ejecutar el hook de compilación para restaurar los archivos generados faltantes;
las entradas sin cambios reutilizan la salida existente.

## Uso

```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
```

### Detección de puntos de entrada

Trailmark rellena automáticamente `graph.entrypoints` para que `attack_surface()`, la propagación de taint y el cruce de límites de privilegios tengan datos con los que trabajar. La detección se ejecuta en cuatro capas, cada una sobrescribiendo la anterior:

1. **Heurística genérica de `main`.** Cualquier función llamada `main` en cualquier lenguaje. Etiquetada como `user_input` / `trusted_internal` / `low`.
2. **Escaneo consciente del framework.** Patrones de decoradores, atributos y visibilidad por lenguaje — véase la tabla a continuación.
3. **`pyproject.toml [project.scripts]`.** Los objetivos CLI explícitos reciben una clasificación de confianza/activo mejorada.
4. **Archivo de anulación local del repositorio.** Los puntos de entrada seleccionados manualmente en `.trailmark/entrypoints.toml` siempre tienen prioridad.

Cobertura de frameworks:

| Lenguaje | Frameworks detectados |
| --- | --- |
| Python | Flask, FastAPI, aiohttp, Click, Typer, Celery |
| JavaScript / TypeScript | NestJS, Next.js (App Router + Pages API), AWS Lambda |
| Java | Spring MVC / WebFlux, JAX-RS, listeners de Kafka, servlets |
| C# | ASP.NET Core, Azure Functions |
| PHP | Atributos `#[Route]` de Symfony + anotaciones heredadas |
| Rust | actix-web, rocket, exportaciones FFI (`#[no_mangle]`, `pub extern "C"`), atributos async-main |
| Solidity | Visibilidad `external` / `public` |
| Cairo / StarkNet | `#[external]`, `#[view]`, `#[l1_handler]`, `#[constructor]` |
| Circom | Declaraciones `component main` |
| Miden Assembly | Directivas `export.<name>` |
| Haskell | `main ::` / `main =` de nivel superior |
| Erlang | Funciones listadas en `-export([...])` |
| Swift | Atributo de aplicación `@main` |
| Objective-C | Selectores del ciclo de vida de `UIApplicationDelegate` (p. ej. `application:openURL:options:`) |
| Kotlin | Anotaciones de Spring MVC / WebFlux (compartidas con Java), métodos del ciclo de vida de componentes Android (`onCreate`, `onReceive`, `onBind`, ...) |
| Dart | Marcadores nativos invocables `@pragma('vm:entry-point')` |
| Go | Registros de la stdlib `http.HandleFunc` / `http.Handle`, registros de manejadores estilo gin/chi/echo `<router>.GET/POST/...` |
| Ruby | Acciones de controladores Rails (clases que heredan de `ApplicationController` / `ActionController::*`), métodos `perform` de workers de Sidekiq |
| C / C++ | Enlace `extern "C"`, `__attribute__((visibility("default")))`, `__declspec(dllexport)` |

Para cualquier cosa que las heurísticas pasen por alto, declare los puntos de entrada explícitamente en `.trailmark/entrypoints.toml` en la raíz del proyecto. El archivo admite tanto entradas de nodo único como basadas en reglas:

```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"
```

Las entradas posteriores anulan a las anteriores cuando dos reglas etiquetan el mismo nodo, así que coloca las reglas generales primero y las correcciones específicas después.

Consulta [docs/entrypoint-patterns.md](https://github.com/trailofbits/trailmark/blob/main/docs/entrypoint-patterns.md) para la referencia completa, incluidos frameworks aún no implementados (Express / Koa / Fastify, Laravel, Cobra, axum, warp, clap y otros) con patrones listos para grep que los contribuidores pueden usar para añadir nuevos detectores.

La detección de Solidity utiliza metadatos del parser en lugar de regex de firmas. Las declaraciones de interfaz se excluyen, y las sobrescrituras derivadas anotan las implementaciones base coincidentes con `solidity_overridden_by` en lugar de eliminar el entrypoint base. Las funciones concretas `public` y `external` siguen siendo entrypoints, incluidas las funciones `view` y `pure`; sus atributos `solidity_visibility`, `solidity_mutability` y de sobrescritura son devueltos por `attack_surface()` para que los llamadores puedan distinguir la exposición de solo lectura y filtrar las implementaciones base sobrescritas. `attack_surface()` incluye atributos de entrypoint específicos del parser cuando están adjuntos al nodo del grafo subyacente.

### Enlaces entre lenguajes y externos

El análisis políglota fusiona los grafos de lenguajes, pero muchas relaciones RPC, FFI, de subprocesos y de host/contrato no son visibles en la sintaxis del código fuente. Declara estas de forma determinista en `.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"
target_external = true         # required because target is unresolved
```

Las referencias pueden ser IDs de nodo exactos o nombres/sufijos únicos. Las referencias ambiguas, los endpoints internos desconocidos, los valores de enumeración no válidos y el TOML mal formado generan `ValueError`. Establecer `source_external = true` o `target_external = true` permite explícitamente ese endpoint sin resolver y crea un nodo proxy. Este archivo es una interfaz de configuración pública estable.

### Limitaciones del análisis

- `entrypoint_paths_to()` informa la alcanzabilidad del grafo de llamadas, no el flujo de datos controlado por el atacante. Utilice los resultados de taint del preanálisis como una señal separada de baja precisión; Trailmark aún no realiza análisis de taint interprocedimental.
- TypeScript resuelve llamadas directas y receptores sencillos asignados con `new ConcreteClass()`. El despacho de interfaces a través de manifiestos, nombres de propiedades computadas, contenedores de inyección de dependencias y otros mecanismos dinámicos sigue siendo de mejor esfuerzo.
- El soporte de SQL está orientado a PostgreSQL y extrae esquemas, tablas, vistas, funciones, procedimientos y dependencias de rutinas/vistas. No es un validador completo de dialectos SQL ni un analizador semántico de consultas.

### API programática

```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` y `PROCEDURE` son aditivos en v0.5.0;
los consumidores que hacen coincidencia exhaustiva de los valores del enum deben añadir casos para ellos.

## Desarrollo

```bash
# Install package and dev dependencies
npm ci
uv sync --all-groups

# Lint and format
uv run ruff check --fix
uv run ruff format

# Type check
uv run --locked ty check

# Tests
uv run pytest -q tests/

# Mutation testing with pytest-gremlins
uv run python -m tests.run_mutations --reviewed --workers=4
uv run python -m tests.mutation_gate

# Full repository mutation campaign
uv run python -m tests.run_mutations --workers=4
```

Los informes de mutación se escriben en `coverage/gremlins/`. Las solicitudes de extracción mutan los archivos Rust/Verus nombrados en `tests/mutation_baseline.json` y aplican la compuerta a las funciones nuevas y modificadas allí. Las campañas completas del repositorio se ejecutan en los pushes a main y mediante el disparador manual del flujo de trabajo de mutación. Las funciones heredadas sin cambios se identifican mediante hashes de código fuente y entran en la compuerta automáticamente cuando se editan. La compuerta rechaza supervivientes no revisados, pruebas/resultados faltantes, errores y tiempos de espera agotados. Las excepciones requieren una razón y una huella digital de la función y la mutación; cambiar esa función requiere revisar sus excepciones nuevamente.

El ejecutor fija pytest-gremlins 1.9.0 y utiliza subprocesos reales de pytest para cada mutante, incluidos fixtures y pruebas parametrizadas. Cada mutante conserva la suite de pruebas seleccionada completa: las pruebas unitarias de componentes se ejecutan primero, seguidas por las pruebas restantes, deteniéndose en el primer fallo. Los mutantes de helpers compartidos conservan las pruebas de todos los lenguajes. Las pruebas permanecen en sus archivos existentes; `tests/mutation_order.py` define el orden, y los componentes desconocidos conservan el orden de recolección. El ejecutor omite el pre-escaneo de cobertura redundante, verifica la línea base limpia y cada orden de pruebas instrumentado distinto, y preserva los metadatos del paquete y los IDs de parámetros exactos al cargar el código mutado.
Estas medidas de compatibilidad abordan problemas del ejecutor y de selección upstream; sus pruebas de control deben pasar antes de actualizar el plugin.
Las actualizaciones de instantáneas (`TRAILMARK_UPDATE_SNAPSHOTS=1`) están deshabilitadas durante CI y las ejecuciones de mutación. Para enfocar una campaña local, pase `--targets` con rutas de código fuente separadas por comas, seguidas de los archivos de prueba relevantes. `--workers=4` ya habilita la ejecución paralela. Use `--test-order=collection` para comparar con el orden original de pytest.

## Licencia

Apache-2.0
Descargar herramienta