Skip to content

feat(#255): /threat-model --format=dragon for OWASP Threat Dragon JSON export#258

Merged
atlas-apex merged 3 commits into
devfrom
feature/GH-255-threat-dragon-format
May 16, 2026
Merged

feat(#255): /threat-model --format=dragon for OWASP Threat Dragon JSON export#258
atlas-apex merged 3 commits into
devfrom
feature/GH-255-threat-dragon-format

Conversation

@atlas-apex

Copy link
Copy Markdown
Collaborator

Summary

  • Adds a --format=markdown|dragon|both flag to /threat-model. Default behaviour (markdown only) is unchanged — backwards compatible.
  • --format=dragon writes <output-dir>/threat-model.json in OWASP Threat Dragon v2 schema. Adopters can open it directly in the Dragon desktop / web app for visual editing, sharing with security teams, and ongoing maintenance.
  • Maps the existing DFD vocabulary 1:1 onto Dragon shapes (external actors → actor, processes → process, data stores → store, trust boundaries → trust-boundary-box, data flows → flow with source.cell / target.cell UUIDs). STRIDE findings attach to their parent shape via data.threats[] with the six schema-required fields (description, mitigation, severity, status, title, type), modelType: STRIDE, and status: Open.
  • Layout is an auto-grid (actors row at y=0, processes at y=200, stores at y=400; x-spaced 200px). Trust-boundary boxes wrap their children with a 40px margin. Dragon's auto-arrange re-flows on first open — the grid is just a sane starting state. Rationale: AgDR-0022.

Testing

  1. Run the smoke test from the repo root:

    bash .claude/skills/threat-model/tests/test_serialize_dragon.sh
    

    Expected: 17 passed, 0 failed. Validates:

    • serialiser writes non-empty JSON to --out
    • top-level Threat Dragon v2 required keys present (version, summary.title, detail.{contributors, diagrams, diagramTop, reviewer, threatTop})
    • every cell has id / shape / zIndex
    • shape counts match the fixture (1 actor, 3 processes, 1 store, 4 flows, 3 boundary boxes = 12 cells)
    • every flow's source.cell / target.cell points at a real cell UUID
    • all 3 fixture threats attach to the correct parent (process / store / flow) with the 6 required fields
    • severity normalises into Dragon's High / Medium / Low enum
    • --strict exits non-zero on bad input (orphan flow source/target)
    • SKILL.md documents --format in frontmatter argument-hint and ## Usage
    • AgDR-0022 exists and captures the Dragon vs TMT vs IriusRisk decision
  2. End-to-end against the bundled fixture:

    python3 .claude/skills/threat-model/serialize_dragon.py \
      .claude/skills/threat-model/fixtures/sample-input.yaml \
      --out /tmp/threat-model.json
    jq '.detail.diagrams[0].cells | length' /tmp/threat-model.json   # → 12
    

    Then open /tmp/threat-model.json in OWASP Threat Dragon (File → Open Existing Threat Model). Click Auto-arrange on the toolbar to re-flow the grid.

  3. Backwards-compat check (default unchanged): invoke /threat-model without any flag and confirm the existing markdown + _lib-audit-history.sh persistence flow still fires, untouched.

Glossary

Term Definition
OWASP Threat Dragon Open-source desktop + web app for creating and editing threat models with STRIDE annotations. Maintained by OWASP.
Threat Dragon v2 JSON The native serialisation format for Threat Dragon models. Schema published at td.vue/src/assets/schema/threat-dragon-v2.schema.json.
STRIDE Microsoft's threat-classification mnemonic — Spoofing, Tampering, Repudiation, Information disclosure, Denial of service, Elevation of privilege.
DFD Data Flow Diagram — shows external actors, processes, data stores, trust boundaries, and labelled data flows. The foundation for STRIDE analysis.
Trust boundary Region in a DFD marking where data crosses a privilege / network / ownership boundary. Threats concentrate at boundary crossings.
trust-boundary-box Threat Dragon shape that renders as a rectangular wrapper around its child shapes, marking a trust boundary. Has data.isTrustBoundary: true.
Auto-grid layout Deterministic, code-free layout that places cells in rows by element class (actors / processes / stores) at fixed y-coordinates, x-spaced by column index. Dragon's auto-arrange re-flows it on first open.
AgDR Agent Decision Record — captures the why behind a technical choice with an options-considered table. AgDR-0022 covers the format choice for this PR.

Closes #255

🤖 Generated with Claude Code

…N export

Adds a `--format` flag to /threat-model so adopters can emit OWASP
Threat Dragon v2 JSON alongside the existing markdown catalogue.
Default behaviour (markdown only) is unchanged for backwards compat.

- Add serialize_dragon.py — stdlib-only Python serialiser that maps
  the skill's DFD + STRIDE findings into Threat Dragon v2 JSON
  (actor/process/store/flow/trust-boundary-box shapes; threats[]
  attached to parent cells with the 6 schema-required fields).
- Use auto-grid layout (actors y=0, processes y=200, stores y=400;
  x-spaced 200px). Trust boundaries wrap their children with a 40px
  margin. Dragon's auto-arrange re-flows on first open.
- Add fixtures/sample-input.yaml + tests/test_serialize_dragon.sh
  (17-case smoke test covering top-level keys, shape-class counts,
  flow ref resolution, STRIDE attachment, severity normalisation,
  --strict bad-input exit, SKILL.md doc presence, AgDR presence).
- Extend SKILL.md with Usage section + Step 6 (serialiser invocation
  + structured-input schema) + an opt-in default rule.
- Add AgDR-0022 capturing the format choice (Dragon v2 vs TMT .tm7
  vs IriusRisk vs OTM vs GraphViz) and the auto-grid layout decision.

Closes #255

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
me2resh added a commit that referenced this pull request May 16, 2026

@atlas-apex atlas-apex left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review: PR #258

Commit: a54041b402e5e74ae23effc8879e6eca844aebeb

The serialiser is well-shaped: schema mapping is faithful (DFD vocabulary → Dragon shapes 1:1, STRIDE findings nest under data.threats[] with all six required fields, severity normalised into the High/Medium/Low enum, flow source/target reference real cell UUIDs, cells emitted in the correct shapes→boundaries→flows order with sensible z-indexes -1/1-3/10), the 17-case smoke test is meaningfully assertive rather than merely structural (cross-class threat-parent placement, dangling-ref detection under --strict, severity enum conformance, and SKILL.md/AgDR cross-checks), and the auto-grid produces a clean starting state that Dragon's own auto-arrange can re-flow. The PyYAML fallback parser is suitably narrow — it cleanly handles the documented input schema (inline maps, block lists of maps, nested keys, quoted/unquoted scalars) and the limits are documented up front ("not a general YAML parser"). Backwards-compat is preserved (default --format=markdown unchanged), and the YAML fallback matches the existing /journey skill convention. One nit: docs/agdr/AgDR-0024-threat-dragon-export.md has id: AgDR-0022 in its YAML frontmatter and references "AgDR-0022" throughout the body and in SKILL.md citations — the renumber appears to have moved only the filename. Worth fixing the frontmatter id: and body references for AgDR-index consistency, but non-blocking.

Verdict

APPROVED


Reviewed by Rex (Code Reviewer Agent)
Reviewed commit: a54041b402e5e74ae23effc8879e6eca844aebeb

@atlas-apex atlas-apex left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approved at 2e5958a — verified diff is exactly the 3-line doc fix (AgDR-0024 frontmatter id 0022 to 0024, plus two SKILL.md citation updates from AgDR-0022 to AgDR-0024). No code changes, no regression risk. LGTM.

@atlas-apex atlas-apex merged commit ef6f504 into dev May 16, 2026
3 checks passed
@atlas-apex atlas-apex deleted the feature/GH-255-threat-dragon-format branch May 16, 2026 09:23
atlas-apex added a commit that referenced this pull request May 16, 2026
…ut (#259)

* feat(#256): /process skill — extract process from code, BPMN 2.0 output

- New skill at .claude/skills/process/SKILL.md that maps a named business
  process by scanning across seven discovery axes (explicit workflow defs,
  queue/job chains, cron triggers, state-column transitions, API
  choreography, existing BPMN/Mermaid, documented steps), interviews only
  on gaps, then emits a lint-clean BPMN 2.0 file the operator can open in
  Camunda Modeler.

- Anchor-scoped discovery (operator supplies process slug + entry point —
  endpoint / state machine / queue job / directory) with reachability
  bounding from the anchor. No exhaustive scans.

- Cross-repo traversal via apexyard.projects.yaml — when a handoff target
  matches a registered project, the skill recurses into that repo (offers
  to clone workspace/<name>/ if missing, default-yes). Unregistered
  targets render as external participant pools.

- generate-bpmn.sh emits valid BPMN 2.0 XML with bpmn:laneSet,
  bpmn:messageFlow for cross-pool handoffs, source citations via
  bpmn:documentation on every element. Pipes through `npx bpmn-auto-layout`
  for <bpmndi> coords; falls back to bare BPMN with warning when Node is
  missing.

- lint.sh wraps `bpmnlint` (recommended ruleset + label-required +
  no-disconnected + no-implicit-split) as the merge gate; overridable via
  per-project .bpmnlintrc.

- AgDR-0024 captures the seven sub-decisions: BPMN 2.0 over alternatives
  (DMN/CMMN/Mermaid sequence/raw flowchart), bpmn-auto-layout over manual
  coords, bpmnlint as the gate, read-first-then-ask over operator-only
  authoring, swimlanes-default vs pools-opt-in, registry-lookup vs
  heuristic URL matching, on-demand cloning offer vs black-box fallback.

- Three test scripts cover discovery (smoke.sh — 18 checks across all
  seven axes on a synthetic Express+Prisma+BullMQ+XState fixture),
  cross-repo registry lookup (test_cross_repo.sh — 6 checks), and BPMN
  emission edge cases (test_bpmn_emit.sh — 21 checks: special-char XML
  escaping, message flows, --pools mode, flow refs, xmllint validity).

- CLAUDE.md skill registry bumped to 44; docs/multi-project.md "How
  skills behave" table updated.

Closes #256

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(#256): renumber AgDR to 0025 — #258 took 0024 during parallel landing

* fix(#256): align AgDR-0025 frontmatter id (renumber missed YAML field)

---------

Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
atlas-apex added a commit that referenced this pull request May 16, 2026
…ies + classifications (#260)

* feat(#257): /dfd skill — extract Data Flow Diagram with trust boundaries + classifications

Introduces /dfd as the canonical Data Flow Diagram producer. The DFD
becomes the source of truth for /threat-model and /compliance-check —
both refactored in this commit to consume from
projects/<name>/architecture/dfd.md instead of regenerating their own
data-flow views.

Six-axis discovery (external actors, processes, data stores, data
flows, trust boundaries, data classifications). Classifications detect
via three additive pathways: code annotations (@pii, @sensitive,
CLASSIFIED:), env-var heuristics (*_SECRET, *_TOKEN, EMAIL_*), and
schema-column heuristics (email, phone, card_number). An optional
explicit registry at docs/data-classification.{md,yaml} overrides
heuristic labels.

Two output formats: Mermaid markdown (default, renders inline on
GitHub, zero new toolchain) and OWASP Threat Dragon v2 JSON (on
--format=dragon, for visual editing in Threat Dragon). The Dragon
serialiser is a pure function over the in-memory model so #255
(/threat-model --format=dragon) can share or import it.

Multi-repo discovery via a new shared helper _lib-multi-repo-trace.sh
(intended to also be consumed by /process #256). Three resolvers:
mrt_resolve_target (hostname/URL/topic → registered project),
mrt_is_third_party (known SaaS vendor detection), mrt_workspace_for
(workspace clone path resolution).

The refactors of /threat-model and /compliance-check are surgical —
Step 1 of /threat-model now reads dfd.md and offers /dfd first if it
doesn't exist; Step 4 of /compliance-check reads the classifications +
external-services list from dfd.md for cross-border-transfer and DPA
detection. Output formats and audit-history persistence contracts in
both consumers are unchanged.

AgDR-0024 captures the design rationale: Mermaid as primary, Threat
Dragon as secondary; classifications as a first-class concept; the
single-source-of-truth refactor; the shared multi-repo trace helper.

Cross-PR coordination:
  - #255 (/threat-model --format=dragon) — shares the Threat Dragon
    serialiser; if #255 lands first with the serialiser inside
    /threat-model, this skill imports from there
  - #256 (/process) — shares the _lib-multi-repo-trace.sh helper; if
    /process extracted its own version first, the consumer that lands
    later should consolidate

Tests (.claude/skills/dfd/tests/smoke.sh, 52 assertions) cover all
three fixtures from the AC: single-service six-axis discovery,
cross-service trust-boundary detection, three-pathway classification
detection. Plus Mermaid generator output shape, Threat Dragon JSON
schema validation, and verification that /threat-model and
/compliance-check actually reference dfd.md.

Closes #257

* fix(#257): renumber AgDR to 0026 — #258 + #259 took 0024 + 0025 during parallel landing

* fix(#257): address Rex blockers — shellcheck SC2221/2222, MD032, lychee 404, AgDR refs

- _lib-multi-repo-trace.sh: drop redundant subset patterns in third-party detector
  (e.g. *api.amplitude.com* covered by broader *amplitude.com*) — clears SC2221/2222.
- dfd/SKILL.md: blank lines around Discovery + Classifications lists — clears MD032.
- dfd/SKILL.md: Threat Dragon schema link now points to the repo root (sub-path 404'd).
- AgDR cross-refs across 5 files renumbered 0024 → 0026 (renumber missed downstream).

---------

Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com>
me2resh added a commit that referenced this pull request Jun 5, 2026
…N export (#258)

* feat(#255): /threat-model --format=dragon for OWASP Threat Dragon JSON export

Adds a `--format` flag to /threat-model so adopters can emit OWASP
Threat Dragon v2 JSON alongside the existing markdown catalogue.
Default behaviour (markdown only) is unchanged for backwards compat.

- Add serialize_dragon.py — stdlib-only Python serialiser that maps
  the skill's DFD + STRIDE findings into Threat Dragon v2 JSON
  (actor/process/store/flow/trust-boundary-box shapes; threats[]
  attached to parent cells with the 6 schema-required fields).
- Use auto-grid layout (actors y=0, processes y=200, stores y=400;
  x-spaced 200px). Trust boundaries wrap their children with a 40px
  margin. Dragon's auto-arrange re-flows on first open.
- Add fixtures/sample-input.yaml + tests/test_serialize_dragon.sh
  (17-case smoke test covering top-level keys, shape-class counts,
  flow ref resolution, STRIDE attachment, severity normalisation,
  --strict bad-input exit, SKILL.md doc presence, AgDR presence).
- Extend SKILL.md with Usage section + Step 6 (serialiser invocation
  + structured-input schema) + an opt-in default rule.
- Add AgDR-0022 capturing the format choice (Dragon v2 vs TMT .tm7
  vs IriusRisk vs OTM vs GraphViz) and the auto-grid layout decision.

Closes #255

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(#255): renumber AgDR to 0024 — 0022 + 0023 landed on dev while #258 was open

* fix(#255): align AgDR frontmatter id + SKILL.md citations to 0024

---------

Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
me2resh added a commit that referenced this pull request Jun 5, 2026
…ut (#259)

* feat(#256): /process skill — extract process from code, BPMN 2.0 output

- New skill at .claude/skills/process/SKILL.md that maps a named business
  process by scanning across seven discovery axes (explicit workflow defs,
  queue/job chains, cron triggers, state-column transitions, API
  choreography, existing BPMN/Mermaid, documented steps), interviews only
  on gaps, then emits a lint-clean BPMN 2.0 file the operator can open in
  Camunda Modeler.

- Anchor-scoped discovery (operator supplies process slug + entry point —
  endpoint / state machine / queue job / directory) with reachability
  bounding from the anchor. No exhaustive scans.

- Cross-repo traversal via apexyard.projects.yaml — when a handoff target
  matches a registered project, the skill recurses into that repo (offers
  to clone workspace/<name>/ if missing, default-yes). Unregistered
  targets render as external participant pools.

- generate-bpmn.sh emits valid BPMN 2.0 XML with bpmn:laneSet,
  bpmn:messageFlow for cross-pool handoffs, source citations via
  bpmn:documentation on every element. Pipes through `npx bpmn-auto-layout`
  for <bpmndi> coords; falls back to bare BPMN with warning when Node is
  missing.

- lint.sh wraps `bpmnlint` (recommended ruleset + label-required +
  no-disconnected + no-implicit-split) as the merge gate; overridable via
  per-project .bpmnlintrc.

- AgDR-0024 captures the seven sub-decisions: BPMN 2.0 over alternatives
  (DMN/CMMN/Mermaid sequence/raw flowchart), bpmn-auto-layout over manual
  coords, bpmnlint as the gate, read-first-then-ask over operator-only
  authoring, swimlanes-default vs pools-opt-in, registry-lookup vs
  heuristic URL matching, on-demand cloning offer vs black-box fallback.

- Three test scripts cover discovery (smoke.sh — 18 checks across all
  seven axes on a synthetic Express+Prisma+BullMQ+XState fixture),
  cross-repo registry lookup (test_cross_repo.sh — 6 checks), and BPMN
  emission edge cases (test_bpmn_emit.sh — 21 checks: special-char XML
  escaping, message flows, --pools mode, flow refs, xmllint validity).

- CLAUDE.md skill registry bumped to 44; docs/multi-project.md "How
  skills behave" table updated.

Closes #256

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(#256): renumber AgDR to 0025 — #258 took 0024 during parallel landing

* fix(#256): align AgDR-0025 frontmatter id (renumber missed YAML field)

---------

Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
me2resh added a commit that referenced this pull request Jun 5, 2026
…ies + classifications (#260)

* feat(#257): /dfd skill — extract Data Flow Diagram with trust boundaries + classifications

Introduces /dfd as the canonical Data Flow Diagram producer. The DFD
becomes the source of truth for /threat-model and /compliance-check —
both refactored in this commit to consume from
projects/<name>/architecture/dfd.md instead of regenerating their own
data-flow views.

Six-axis discovery (external actors, processes, data stores, data
flows, trust boundaries, data classifications). Classifications detect
via three additive pathways: code annotations (@pii, @sensitive,
CLASSIFIED:), env-var heuristics (*_SECRET, *_TOKEN, EMAIL_*), and
schema-column heuristics (email, phone, card_number). An optional
explicit registry at docs/data-classification.{md,yaml} overrides
heuristic labels.

Two output formats: Mermaid markdown (default, renders inline on
GitHub, zero new toolchain) and OWASP Threat Dragon v2 JSON (on
--format=dragon, for visual editing in Threat Dragon). The Dragon
serialiser is a pure function over the in-memory model so #255
(/threat-model --format=dragon) can share or import it.

Multi-repo discovery via a new shared helper _lib-multi-repo-trace.sh
(intended to also be consumed by /process #256). Three resolvers:
mrt_resolve_target (hostname/URL/topic → registered project),
mrt_is_third_party (known SaaS vendor detection), mrt_workspace_for
(workspace clone path resolution).

The refactors of /threat-model and /compliance-check are surgical —
Step 1 of /threat-model now reads dfd.md and offers /dfd first if it
doesn't exist; Step 4 of /compliance-check reads the classifications +
external-services list from dfd.md for cross-border-transfer and DPA
detection. Output formats and audit-history persistence contracts in
both consumers are unchanged.

AgDR-0024 captures the design rationale: Mermaid as primary, Threat
Dragon as secondary; classifications as a first-class concept; the
single-source-of-truth refactor; the shared multi-repo trace helper.

Cross-PR coordination:
  - #255 (/threat-model --format=dragon) — shares the Threat Dragon
    serialiser; if #255 lands first with the serialiser inside
    /threat-model, this skill imports from there
  - #256 (/process) — shares the _lib-multi-repo-trace.sh helper; if
    /process extracted its own version first, the consumer that lands
    later should consolidate

Tests (.claude/skills/dfd/tests/smoke.sh, 52 assertions) cover all
three fixtures from the AC: single-service six-axis discovery,
cross-service trust-boundary detection, three-pathway classification
detection. Plus Mermaid generator output shape, Threat Dragon JSON
schema validation, and verification that /threat-model and
/compliance-check actually reference dfd.md.

Closes #257

* fix(#257): renumber AgDR to 0026 — #258 + #259 took 0024 + 0025 during parallel landing

* fix(#257): address Rex blockers — shellcheck SC2221/2222, MD032, lychee 404, AgDR refs

- _lib-multi-repo-trace.sh: drop redundant subset patterns in third-party detector
  (e.g. *api.amplitude.com* covered by broader *amplitude.com*) — clears SC2221/2222.
- dfd/SKILL.md: blank lines around Discovery + Classifications lists — clears MD032.
- dfd/SKILL.md: Threat Dragon schema link now points to the repo root (sub-path 404'd).
- AgDR cross-refs across 5 files renumbered 0024 → 0026 (renumber missed downstream).

---------

Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants