---
name: analisis-estructural-trailmark
description: Ejecuta un analisis estructural completo de codigo mediante Trailmark 0.2.x, construyendo un grafo de codigo y calculando hotspots de complejidad, flujos de taint, radio de explosion, fronteras de privilegio y superficie de ataque. Ideal para priorizar auditorias de seguridad con datos estructurales detallados.
allowed-tools: Bash Read Grep Glob
license: CC-BY-SA-4.0
metadata:
  id: 87c69503
  slug: analisis-estructural-trailmark
  titulo: "Analisis Estructural con Trailmark"
  servicio: Seguridad
  categoria_recurso: IA-Generativa
  tipo: analisis
  nivel: avanzado
  idioma: es
  idioma_original: en
  acceso: gratis
  precio_eur: 0
  plataformas: [CLI, Python, vivisect, trailmark]
  dependencias: [trailmark>=0.2.x, python3, uv]
  licencia: { spdx: CC-BY-SA-4.0, redistribuible: true, uso_comercial: true }
  fuente:
    repo: trailofbits/skills
    url: https://github.com/trailofbits/skills/tree/main/plugins/trailmark/skills/trailmark-structural
    commit: c070b9b
    autor: trailofbits
    nombre_original: trailmark-structural
    duplicados_en: []
  seguridad: { veredicto: seguro, riesgo: bajo, escaneado: "2026-06-14", motor: "grep-estatico+auditor-llm" }
  ficha:
    que_hace: "Analiza la estructura interna de un codebase para identificar puntos criticos de seguridad como hotspots, taint flows y superficie de ataque."
    como_lo_hace: "Construye un grafo con QueryEngine de Trailmark, ejecuta los cuatro pases de preanálisis y devuelve un payload JSON con todos los resultados estructurales."
  content_hash: "87c69503c8a378e5dd286d4d26607355ae62843cb01154ff1814ecba7414d151"
  version: 1.0.0
---

# Trailmark Structural Analysis

Builds a Trailmark graph and runs `engine.preanalysis()` to compute all
four pre-analysis passes.

## When to Use

- Vivisect Phase 1 needs full structural data (hotspots, taint, blast radius, privilege boundaries)
- Detailed pre-analysis passes for a specific target scope
- Generating complexity and taint data for audit prioritization

## When NOT to Use

- Quick overview only (use `trailmark-summary` instead)
- Ad-hoc code graph queries (use the main `trailmark` skill directly)
- Target is a single small file where structural analysis adds no value

## Rationalizations to Reject

| Rationalization | Why It's Wrong | Required Action |
|-----------------|----------------|-----------------|
| "Summary analysis is enough" | Summary skips taint, blast radius, and privilege boundary data | Run full structural analysis when detailed data is needed |
| "One pass is sufficient" | Passes cross-reference each other — taint without blast radius misses critical nodes | Run all four passes |
| "Tool isn't installed, I'll analyze manually" | Manual analysis misses what tooling catches | Report "trailmark is not installed" and return |
| "Empty pass output means the pass failed" | Some passes produce no data for some codebases (e.g., no privilege boundaries) | Return full output regardless |

## Usage

The target directory is passed via the `args` parameter.

## Execution

**Step 1: Check that trailmark is available.**

```bash
trailmark analyze --help 2>/dev/null || \
  uv run trailmark analyze --help 2>/dev/null
```

If neither command works, report "trailmark is not installed"
and return. Do NOT run `pip install`, `uv pip install`,
`git clone`, or any install command. The user must install
trailmark themselves.

**Step 2: Detect languages with Trailmark's parse API.**

```bash
python3 - "{args}" <<'PY'
import json
import sys

from trailmark.parse import detect_languages

print(json.dumps(detect_languages(sys.argv[1])))
PY
```

If the import fails, rerun the same snippet with `uv run python - "{args}"`.
If the result is `[]`, report "Trailmark found no supported languages under
target" and return.

**Step 3: Run the full structural analysis via `QueryEngine`.**

Run this snippet with `python3`. If the import fails, rerun the same snippet
under `uv run python - "{args}"`.

```bash
python3 - "{args}" <<'PY'
import json
import sys

from trailmark.parse import detect_languages
from trailmark.query.api import QueryEngine

target = sys.argv[1]
languages = detect_languages(target)
engine = QueryEngine.from_directory(target, language="auto")
preanalysis = engine.preanalysis()

def summarize_subgraph(name: str, limit: int = 25) -> dict[str, object]:
    nodes = engine.subgraph(name)
    return {
        "count": len(nodes),
        "sample_ids": [node["id"] for node in nodes[:limit]],
    }

payload = {
    "languages": languages,
    "summary": engine.summary(),
    "preanalysis": preanalysis,
    "attack_surface": engine.attack_surface()[:25],
    "hotspots": engine.complexity_hotspots(10)[:25],
    "subgraphs": {
        name: summarize_subgraph(name)
        for name in engine.subgraph_names()
    },
}

print(json.dumps(payload, indent=2))
PY
```

**Step 4: Verify the output.**

The output should include:
- `languages`
- `summary`
- `preanalysis`
- `hotspots` (possibly empty)
- `subgraphs` with counts and sample IDs

Some subgraphs may have zero nodes for some codebases (this is
normal). Return the full JSON payload regardless.
