Skip to content

Releases: oocx/tfplan2md

v1.45.2

Choose a tag to compare

@github-actions github-actions released this 05 Jun 11:49

Plan status / drift regressions fixed (Issue 661)

Two regressions in plan status rendering have been fixed. Scope is limited to the plan-status banner and drift-section filtering for no-change plans.

🐛 Bug fixes

  • False "Plan is not applyable" warning suppressed for no-change plans.
    When Terraform produces an effective no-op plan (no resource changes, no drift), the applyable = false flag in the plan JSON could trigger a ⛔ Plan is not applyable warning banner even though the plan posed no real problem. The condition now only fires the banner when the plan is also either errored or genuinely actionable (has changes or drift), matching what practitioners actually need to act on.

  • Drift section no longer emits noise entries for no-op drift.
    For plans that recorded drift metadata but where every drift entry was a no-op (unchanged resources), the drift section previously rendered empty or no-op blocks. The fix applies the same display-filtering semantics already used for normal resource changes: no-op and fully suppressed drift entries are hidden, keeping the report free of noise for effectively clean baselines.

📸 Screenshots

No false warning — no-change plan renders cleanly

No-change plan: no false non-applyable warning

Warning correctly shown for actionable non-applyable plans

Actionable non-applyable plan: warning still rendered

🔗 Commits

  • f344afb fix: suppress non-applyable banner and drift noise for no-change/no-drift baselines

v1.45.1

Choose a tag to compare

@github-actions github-actions released this 02 Jun 06:30

1.45.1 (2026-06-02)

🐛 Bug Fixes

  • disable musl arm64 AOT in Docker build (c3109e1)
  • exempt src Dockerfile from work-item release artifacts check (974a631)

v1.45.0

Choose a tag to compare

@github-actions github-actions released this 01 Jun 13:53

Inline relevant attributes

tfplan2md now renders Terraform plan context inline on the affected resource cards instead of isolating relevant_attributes[] at the bottom of the report. This makes replacement cascades and upstream dependencies visible where reviewers make decisions.

✨ Features

  • Replaced or destroyed resources now show inline ⚠️ Forced replacement callouts when a replace_paths entry traces back to an upstream relevant attribute.
  • Replaced or destroyed resources also show inline 🔗 Depends on: / 🔗 Also depends on: context for correlated upstream inputs.
  • Upstream inputs that are themselves changing in the same plan are highlighted as changing in this plan.
  • Uncorrelated plan inputs are preserved in a collapsible 🔗 Other plan inputs section near the end of the report.

📚 Documentation

  • Updated docs/features.md to describe the new inline relevant-attribute annotations and fallback details block.

📸 Screenshots

Inline annotations

Inline annotations

Fallback inputs

Fallback inputs

🔗 Commits

  • 1dc93917 feat: implement inline relevant attributes (Tasks 1-7, partial - build fixes in progress)

🚨 Breaking changes

None.

v1.44.0

Choose a tag to compare

@github-actions github-actions released this 19 May 20:21

Multi-Platform Docker Image Build (linux/amd64 + linux/arm64)

The official Docker image is now published as a multi-platform manifest supporting both linux/amd64 and linux/arm64. Pulls on ARM64 hosts (e.g., Apple Silicon, AWS Graviton, Raspberry Pi) will automatically receive a native binary without any extra flags.

✨ Features

  • ARM64 Docker image support. The ghcr.io/oocx/tfplan2md image now includes a native linux/arm64 layer alongside the existing linux/amd64 layer. Docker automatically selects the right layer based on the host architecture.

🔗 Commits

  • cc4de0cf feat: enable multi-platform Docker image build (linux/amd64, linux/arm64)

v1.43.3

Choose a tag to compare

@github-actions github-actions released this 16 May 15:33

Security Fixes: CodeQL Bad HTML Filtering Regexp and Supply-Chain Pinning

This patch resolves five GitHub security alerts — three CodeQL high-severity findings and two OpenSSF Scorecard supply-chain findings — with no change to any user-facing behaviour.

🔒 Security fixes

Fixed incomplete HTML comment regex in embedded highlight.js (Alerts #42, #43, #44)

Problem: CodeQL rule js/bad-html-filtering-regexp (CWE-185) flagged two regex patterns inside the minified highlight.js 11.9.0 bundle that is embedded inline in all three HTML wrapper templates:

  • e.COMMENT(/<!--/, /-->/) — the end pattern /-->/ does not match the alternative HTML5 comment terminator --!>, making it an incomplete HTML comment filter.
  • /<![a-zA-Z]/ — flagged as a potential overly-broad tag filter.

Fix: Patched both patterns directly in all three templates (a minimal inline fix rather than a full library upgrade):

  • /-->//-->|--!>/ — now handles both valid HTML5 comment terminators.
  • /<![a-zA-Z]//<![A-Z]/ — XML/SGML declarations (<!DOCTYPE, <!ELEMENT, etc.) always use uppercase; this change is semantically equivalent given that highlight.js compiles all patterns with the i (case-insensitive) flag for HTML/XML mode.

Templates updated:

  • src/tools/Oocx.TfPlan2Md.HtmlRenderer/templates/github-wrapper.html
  • src/tools/Oocx.TfPlan2Md.HtmlRenderer/templates/github-wrapper-light.html
  • src/tools/Oocx.TfPlan2Md.HtmlRenderer/templates/azdo-wrapper.html

Pinned SLSA generator reusable workflow to immutable SHA (Alert #113)

Problem: The SLSA provenance generation step in .github/workflows/release.yml referenced the slsa-framework/slsa-github-generator reusable workflow by the mutable tag @v2.1.0. If the tag were moved to a different commit (intentionally or through a supply-chain attack), the release pipeline would silently run different code.

Fix: Replaced the mutable tag reference with the immutable commit SHA for v2.1.0:

# Before
uses: slsa-framework/slsa-github-generator/...@v2.1.0

# After
uses: slsa-framework/slsa-github-generator/...@f7dd8c54c2067bafc12ca7a55595d5ee9b75204a # v2.1.0

Pinned Alpine package versions in Dockerfile (Alert #99)

Problem: src/Dockerfile installed seven Alpine packages (upx, clang, build-base, zlib-dev, linux-headers, bash, lld) without version constraints. While the base image was already digest-pinned, the packages themselves were resolved from the Alpine package repository at build time, introducing a supply-chain risk.

Fix: All seven packages are now pinned to the exact versions present in the Alpine 3.23 package index that corresponds to the already-pinned base image digest:

RUN apk add --no-cache \
    upx=5.0.2-r0 \
    clang=21.1.2-r2 \
    build-base=0.5-r3 \
    zlib-dev=1.3.2-r0 \
    linux-headers=6.16.12-r0 \
    bash=5.3.3-r1 \
    lld=21.1.2-r1

ℹ️ Maintainer action required (not fixed by code)

Two Scorecard alerts require GitHub repository settings changes that cannot be applied via a code commit:

Alert Required action
#103 Code-Review (High) Settings → Branches → main → enable "Require a pull request before merging" (≥ 1 approval)
#48 Branch-Protection (High) Settings → Branches → main → enable full branch protection (status checks, dismiss stale reviews, include admins)

🔗 Commits

  • afb11db fix: pin SLSA generator to SHA digest (alert #113)
  • 010a79a fix: update highlight.js HTML comment regex to prevent CodeQL alerts (#42 #43 #44)
  • 5a220b4 fix: pin Alpine package versions in Dockerfile (alert #99)

v1.43.2

Choose a tag to compare

@github-actions github-actions released this 16 May 13:29

1.43.2 (2026-05-16)

🐛 Bug Fixes

  • docker: remove --locked-mode from Dockerfile to fix ILCompiler version mismatch (0f0ff8a)
  • workflow: refresh main project NuGet lock for locked-mode restore (810f1f8)
  • workflow: remove explicit AOT package refs that broke docker publish (82b3249)
  • workflow: stabilize locked restore across CI and Docker SDK contexts (9d54c27)

v1.43.1

Choose a tag to compare

@github-actions github-actions released this 13 May 06:01

Pending import no-op status fix (Issue 123)

This bug-fix release resolves a false-positive status in Terraform refactoring output. Scope is limited to import-status classification and related rendered report output.

🐛 Bug fixes

  • Fixed pending importing.id + no-op resources being mislabeled as already imported.
  • Pending imports now render as ✅ Ready while keeping existing moved-resource behavior unchanged.

📸 Screenshots

After

Pending imports now render as Ready

🔗 Commits

  • a93d7ea0 Fix false “already imported” status for pending Terraform imports

v1.43.0

Choose a tag to compare

@github-actions github-actions released this 30 Apr 22:31

Terraform 1.14 / 1.15 Plan-JSON Support

tfplan2md now renders the new fields introduced by Terraform 1.14 and 1.15 — action invocations, plan-context status, drift detection, relevant attributes, and deprecation warnings — all without any change to your CLI invocation. Plans from Terraform 1.13 and earlier are unaffected.

✨ Features

🎬 Action invocations (Terraform 1.14)

Terraform 1.14 adds action_invocations[] and deferred_action_invocations[] to the plan JSON, produced by provider-shipped Actions (e.g. aws_lambda_invoke, aws_cloudfront_create_invalidation) and by lifecycle { action_trigger { … } } blocks. These are now rendered inline under the resource that triggers them, using an #### 🎬 Actions H4 section inside each resource's collapsible block. Deferred actions are prefixed and include a "will run on a subsequent apply" callout. Actions with no matching resource section (orphan/invoke-mode) appear in a new top-level ## 🎬 Other Actions section.

Inline action invocations under a resource block

🌀 Drift detection (Terraform 1.14)

When resource_drift[] is non-empty — meaning Terraform detected that real-world state diverged from what the state file recorded — a ## 🌀 Drift Detected section now appears in the report, listing each drifted resource in the same collapsible before/after format used for resource changes.

Drift Detected section

🛑 Plan status banners (Terraform 1.14)

The plan booleans errored, applyable, and complete are now read. When any of them signals a non-ordinary state, a blockquote banner is injected immediately after the report title:

  • 🛑 Plan errored — when errored: true
  • Plan is not applyable — when applyable: false
  • ⚠️ Plan is incomplete — when complete: false

All three can appear together.

Plan status banners for an errored, non-applyable, incomplete plan

📋 Relevant attributes (Terraform 1.14)

When relevant_attributes[] is present, a ## Relevant Attributes section is rendered with a two-column Resource | Attribute path table, making upstream dependencies that triggered cascading changes visible to reviewers.

Relevant Attributes table

⚠️ Deprecation warnings (Terraform 1.15)

Terraform 1.15 adds a deprecated string to configuration.root_module.variables[*] and configuration.root_module.outputs[*]. Any variable or output that is both deprecated and referenced by the plan now produces a warning entry in the ### Warnings section of the Code Analysis Summary, showing the name and the deprecation message from the Terraform configuration.

Deprecation warning for a deprecated variable

Backwards compatibility

All five rendering additions are strictly additive. Plans produced by Terraform 1.13 and earlier (which omit these fields) render byte-for-byte identically to the previous version.

🐛 Bug fixes

  • Deprecation warnings silently dropped when no SARIF scan findings were present. CodeAnalysisSectionRenderer returned early with "No code analysis findings were reported" whenever the SARIF total count was zero, even when deprecation warnings existed. Fix: the early-return now requires both SARIF count and warnings count to be zero; the SARIF severity table is only rendered when there are actual SARIF findings.

📸 Screenshots

See inline screenshots above for each feature area.

🔗 Commits

  • 60aee150 feat(parsing): add Terraform 1.14/1.15 action and relevant-attribute records
  • d3a1765a feat(parsing): extend TerraformPlan with optional Terraform 1.14/1.15 fields
  • d0f4820d feat(parsing): add ConfigurationDeprecationReader helper
  • 3f7e96ff feat(features/122): plan-status banner, drift, relevant attrs, actions, deprecations (Tasks 5-13)
  • e81027fd fix(feature/122): fix deprecation warnings silently dropped when no SARIF findings; add sealed to PlanStatusModel/RelevantAttributeModel

v1.42.1

Choose a tag to compare

@github-actions github-actions released this 28 Apr 21:43

1.42.1 (2026-04-28)

🐛 Bug Fixes

  • improve OpenSSF scorecard score (23d06fa)

v1.42.0

Choose a tag to compare

@github-actions github-actions released this 25 Apr 20:44

Summary table now shows imports/moves and hides empty rows

The Summary table at the top of every report now surfaces Terraform import and moved blocks as their own rows, hides any action row whose count is 0, and falls back to a clean "No changes" message when no row has any content. Reports stay focused on what actually changes.

✨ Enhancements

Imports and moves are now first-class summary rows

📥 Import and 🔀 Move rows are added to the Summary table whenever the plan contains resources brought in via import blocks or relocated via moved blocks. Each row uses the same Count and Resource Types breakdown as the existing action rows, so refactoring activity is visible at a glance without scrolling to the per-resource details.

## Summary

| Action | Count | Resource Types |
| -------- | ------- | ---------------- |
| ➕ Add | 2 | 1 azurerm_resource_group<br/>1 azurerm_virtual_network |
| 📥 Import | 2 | 1 azurerm_resource_group<br/>1 azurerm_storage_account |
| 🔀 Move | 1 | 1 azurerm_virtual_network |
| **Total** | **2** | |

Imports and moves are reported alongside the action buckets (a single change can appear in both an action row and an Import/Move row). The Total still reflects only resource changes (add + change + replace + destroy), so the existing Azure DevOps tfplan2md_haschanges pipeline variable behavior is unchanged.

Zero-count rows are hidden

Rows whose count is 0 are no longer rendered, so a create-only plan now shows just the Add row instead of three empty Change, Replace, and Destroy rows. This keeps the summary tight and matches the new behavior for Import/Move rows (they only appear when there is something to report).

Before:

| ➕ Add | 2 | 1 azurerm_resource_group<br/>1 azurerm_storage_account |
| 🔄 Change | 0 |  |
| ♻️ Replace | 0 |  |
| ❌ Destroy | 0 |  |
| **Total** | **2** | |

After:

| ➕ Add | 2 | 1 azurerm_resource_group<br/>1 azurerm_storage_account |
| **Total** | **2** | |

"No changes" replaces the empty table

When every row would be hidden — including the new Import/Move rows — the renderer keeps the existing "No changes" paragraph in place of an empty table.

📚 Documentation

  • docs/features.md replaces the old "No-Changes Summary" section with a new "Concise Summary Table" section that documents both the import/move rows and the zero-count filtering.

🔗 Commits

  • ed654f1 feat: add imports/moves to summary table and hide zero-count rows
  • 64a34c4 docs: clarify imports/moves are orthogonal to action buckets