Skip to content

feat: v0.3.0 — broadcast-safety fix, reverse tool, validator & MCP hardening - #7

Merged
hishamkaram merged 1 commit into
mainfrom
feat/v0.3.0-audit-improvements
May 15, 2026
Merged

feat: v0.3.0 — broadcast-safety fix, reverse tool, validator & MCP hardening#7
hishamkaram merged 1 commit into
mainfrom
feat/v0.3.0-audit-improvements

Conversation

@hishamkaram

Copy link
Copy Markdown
Owner

Context

A deep, multi-iteration expert audit of the whole project — every finding verified against primary sources (Slack Block Kit docs, the MCP go-sdk, slack-go, goldmark) rather than assumed. Targets a v0.3.0 release.

Security (the headline)

h2–h6 headings — and any heading routed to the section.mrkdwn fallback (a long h1, or an h1 containing a link/image/inline code) — only escaped the emphasis markers * _ ~ \``, **not** < > &. So ## <!channel>inrich_textmode emitted a **live broadcast token**. Now entity-escaped via the same gate the markdown_block emitter uses;handleFallbackand the blockquote unknown-child path were hardened the same way.allow_broadcasts/preserve_mention_tokens` still honored.

Regression check: ## <!channel>*&lt;!channel&gt;*.

Correctness fixes

  • splitter: SplitText no longer cuts inside a multi-byte UTF-8 rune for un-breakable tokens (long CJK runs, non-ASCII URLs) — the hard-cut steps back to a rune boundary. Fuzz target gained multibyte seeds + a utf8.ValidString invariant.
  • converter: long-heading section.mrkdwn fallback truncation is rune-safe and strips a dangling \ that could escape the closing *.

Validator completeness

Per-element rules added against verified Slack limits: buttons (text/value/url/action_id), context blocks (≤10 elements), table blocks (≤100 rows / ≤20 cols / ≤20 column_settings), image titles (≤2000), section accessories. New surface-aware ValidateForSurface (modal/home → 100-block ceiling).

New features

  • block_kit_to_markdown — 6th MCP tool, inverse conversion (new internal/reverse package; lossy, reports warnings).
  • MCP tool annotations (readOnlyHint, openWorldHint, titles) on all 6 tools.
  • block-kit-cheatsheet MCP resource + format_for_slack MCP prompt.
  • surface input on validate_block_kit / lint_block_kit.

Hardening / hygiene

  • Options.MaxNestingDepth (default 100) → ErrInputTooDeeplyNested; MaxInputBytes bounds bytes, not structural depth.
  • return_preview_url is now a real opt-out (*bool); unknown split values rejected; non-loopback bind warning.
  • slack-go/slack v0.23.0 → v0.23.1.
  • CI coverage gate now enforces ≥80% per package, not just overall.

Verification

  • make test-race — all packages pass, coverage 80.0–95.9% (overall ~88%)
  • make lint 0 issues · make vet clean · make vuln clean
  • make fuzz 30s — 1.3M execs, no UTF-8 invariant violations
  • Every change ships with table-driven tests; new internal/reverse at 87.5%

CHANGELOG [0.3.0] section is in place for the GoReleaser flow.

…rdening

Security:
- converter: h2-h6 headings (and any heading routed to the section.mrkdwn
  fallback) now entity-escape < > & in the heading text. The fallback
  previously escaped only emphasis markers, so `## <!channel>` in
  rich_text mode emitted a live broadcast. handleFallback and the
  blockquote unknown-child path were hardened the same way.

Added:
- server: block_kit_to_markdown tool (inverse conversion; lossy, warns)
- server: MCP tool annotations on all six tools
- server: block-kit-cheatsheet MCP resource + format_for_slack prompt
- validator: button/context/table/image-title/section-accessory rules
- validator: surface-aware validation (modal/home 100-block ceiling)
- converter: MaxNestingDepth guard (ErrInputTooDeeplyNested)
- internal/reverse package; block_kit re-exports the new surface

Changed:
- server: return_preview_url is a real opt-out (*bool)
- server: convert rejects unknown split values; non-loopback bind warning
- deps: slack-go/slack v0.23.0 -> v0.23.1

Fixed:
- splitter: SplitText no longer cuts inside a multi-byte UTF-8 rune
- converter: long-heading fallback truncation is rune-safe, no dangling \

ci: coverage gate now enforces >=80% per package, not just overall.
@hishamkaram
hishamkaram merged commit 2981544 into main May 15, 2026
7 checks passed
@hishamkaram
hishamkaram deleted the feat/v0.3.0-audit-improvements branch May 15, 2026 22:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant