Architecture

Technical architecture based on arc42 documentation standard. Clean separation, extensible design, security-first.

System Overview

tfplan2md converts Terraform plan JSON into Markdown reports optimized for pull request reviews.

📄

Input

Terraform Plan JSON

terraform show -json
⚙️

tfplan2md

Parse · Transform · Render

📝

Output

Markdown Report

GitHub / Azure DevOps PR

Quality Goals

Priority 1

Security

Mask sensitive values by default · FROM scratch container · AOT-compiled static binary · Non-root user (UID 1654) · No shell · Minimal attack surface · Zero third-party runtime dependencies in the main CLI

Priority 2

Reliability

Handle malformed JSON gracefully · Validate all markdown output · Comprehensive test coverage

Priority 3

Usability

Simple CLI · Sensible defaults · Clear error messages · Zero configuration needed

Priority 4

Maintainability

Clean architecture · Immutable models · Pure functions · Modern C# patterns

Priority 5

Extensibility

Built-in templates · Resource-specific renderers · Provider-specific handling

Priority 6

Performance

Fast startup for CI/CD · Handle large plans efficiently · 2.1 MB Docker image · AOT compilation with aggressive trimming

Core Components

Clean separation of concerns with immutable data models and pure transformation functions.

🎯

CLI

Command-line parsing and orchestration. Handles user input, loads configuration, coordinates workflow.

CliParser.cs HelpTextProvider.cs
📦

Parsing

Terraform plan JSON parsing into immutable domain models using System.Text.Json.

TerraformPlan.cs TerraformPlanParser.cs
🔄

Model Building

Transform domain models into report models. Build resource summaries, group by module, apply inline diffing.

ReportModel.cs Summaries/*.cs
✍️

Rendering

Pure C# renderers generate markdown in a single pass. Built-in report, summary, and resource-specific renderers replace runtime template loading.

MarkdownRenderer.cs ReportRenderer.cs ResourceRendererRegistry.cs
☁️

Azure Utilities

Azure-specific functionality: principal ID mapping, resource ID parsing, role assignment formatting.

PrincipalMapper.cs azurerm/* templates
🔒

Security

Sensitive value detection and masking. AOT-compiled static binary in a FROM scratch container with no third-party runtime dependencies in the main CLI.

--show-sensitive flag FROM scratch + UPX-compressed binary

Technology Stack

Compilation
NativeAOT (linux-musl-x64)
Ahead-of-time compilation to native executable with aggressive trimming
Language
C# 13
Modern language features: records, pattern matching, file-scoped namespaces
JSON Parser
System.Text.Json
Parse Terraform plan JSON with built-in .NET library
Rendering
Pure C# Renderers
Render markdown through built-in default, summary, and resource-specific renderer classes
Container Base
FROM scratch
Scratch base with a single UPX-compressed NativeAOT binary (2.1 MB) — no shell, no runtime, non-root user
Test Framework
TUnit 1.9.26
Unit and integration tests with comprehensive coverage, async-first design, and real-time progress reporting
Markdown Linter
markdownlint-cli2 0.20.0
Validate markdown output for GitHub/Azure DevOps compatibility

Architectural Patterns

Immutability

All data models are immutable records. No mutable shared state. Pure functions for transformations.

✅ Thread-safe, predictable, easier to reason about

Renderer-Driven

Built-in renderers generate markdown directly in C#. Resource-specific overrides plug into a shared registry.

✅ Compile-time safety, simpler debugging, consistent output

Separation of Concerns

Clear boundaries: Parsing → Model Building → Rendering. Each component has single responsibility.

✅ Testable, maintainable, modular

Security by Default

Sensitive values masked unless explicitly shown. FROM scratch containers with AOT-compiled static binaries. Non-root user, no shell, zero third-party runtime dependencies in the main CLI.

✅ Safe for CI/CD, minimal attack surface, sub-second startup

Architecture Decision Records

Key technical decisions and architectural patterns that shape tfplan2md. These guide consistent implementation across features.

Pure C# Rendering

Rendering moved out of Scriban templates and into statically typed C# renderer classes. The user-facing template surface is now limited to built-in `default` and `summary` modes.

Decision: Use direct C# rendering for markdown generation. This removes runtime template loading, improves compile-time safety, and keeps formatting behavior in one debuggable code path.

NativeAOT with FROM scratch

Ahead-of-time compilation produces static native executables for containers and release assets. The main Docker image is now 2.1 MB while keeping the fastest possible startup time.

Benefits: Minimal attack surface, no shell, non-root user (UID 1654), sub-second startup in CI/CD, and compact distribution for both containers and standalone binaries.

Modern C# 13 Patterns

Records for immutable data models, file-scoped namespaces, nullable reference types, pattern matching. Comprehensive XML documentation (including private members) for AI-assisted development.

Benefits: Thread-safe, predictable, easier to reason about. Supports 100% AI-assisted development workflow with GitHub Copilot multi-model approach.

CSS Layers for Website Examples

CSS @layer isolates rendered example styles from website page styles. Examples use @layer examples with lower cascade priority than website styles.

Benefits: Prevents specificity conflicts. Examples remain readable while website styles always win conflicts. Clean separation between content and presentation layers.

Resource-Specific Renderers with ViewModels

Complex resources (firewall rules, NSG rules, role assignments, variable groups, build definitions) use specialized renderers with ViewModel pattern. C# factories precompute semantic diffs, match items by key, and format before/after comparisons.

Benefits: Testable C# logic for complex merging and matching. Renderers iterate preformatted rows and deliver semantic diffs without runtime template limitations.

Single-Pass Report Rendering

Direct renderer dispatch replaces render-then-replace flows. The main report renderer orchestrates headers, summaries, resources, outputs, and provider overrides in one pass.

Benefits: No anchors or regex replacement. Explicit, debuggable renderer selection. No wasted computation. Easier testing and clearer ownership of rendering behavior.

Markdig for Platform-Specific HTML

Standalone HtmlRenderer converts markdown to HTML with GitHub and Azure DevOps flavors. GitHub strips style attributes; Azure DevOps preserves them for theme support.

Use Case: Visual testing, website examples, and screenshot generation. Wrapper templates with a content placeholder provide a development-friendly approximation.

Playwright for Visual Regression

ScreenshotGenerator uses Playwright and Chromium for automated screenshot capture with full-page and targeted element support.

CI Integration: Cross-platform, headless-only, actionable error messages, and union bounding boxes for multiple matches enable visual regression pipelines.

DiagnosticContext for Debug Output

Optional diagnostics are collected throughout the pipeline and appended with a single debug flag.

Benefits: Non-intrusive when disabled, cleanly separated from business logic, and easy to extend with new diagnostic categories.

Report Metadata for Build Traceability

Every report includes tfplan2md version, git commit hash, generation timestamp, and Terraform version metadata.

Benefits: Provides an audit trail for debugging, deterministic tests through a mockable metadata provider, and optional suppression with --hide-metadata.

TUnit for Async-First Testing

Modern test framework with true async support, real-time progress reporting, parallel execution, and comprehensive coverage.

Benefits: Faster feedback than older frameworks, better diagnostics, and close alignment with modern C# and AI-assisted workflows.

Terraform Show Approximation

Development scripts can generate synthetic plan JSON from config and state without running terraform plan.

Use Case: Speeds up template development and experimentation, but remains an approximation that is not suitable for production use.

Complete Architecture Documentation

This page provides a high-level overview. For complete details including building block views, runtime scenarios, deployment architecture, and design decisions, see the full arc42 documentation.