#!/usr/bin/env bash # dry-run-publish.sh # Pre-flight a Confluence storage body before posting. Runs: # - format sanity (storage XHTML, no wiki markup, no markdown fences) # - secret / PII grep (BLOCKER) # - macro sanity (every {code} / {plantuml} / panel is in storage form) # - PlantUML parse (if plantuml on $PATH) # - size sanity (over 300 lines needs justification header) # # Usage: # bash scripts/dry-run-publish.sh # # Exit codes: # 0 = ready to post # 1 = REVISE (MAJOR or MINOR issues found) # 2 = BLOCK (BLOCKER issues found) set -u if [[ $# -lt 1 ]]; then echo "Usage: $0 " >&2 exit 1 fi DRAFT="$1" if [[ ! -f "$DRAFT" ]]; then echo "Draft not found: $DRAFT" >&2 exit 2 fi BLOCK=0 MAJOR=0 MINOR=0 note_block() { echo " [BLOCK] $1"; BLOCK=1; } note_major() { echo " [MAJOR] $1"; MAJOR=1; } note_minor() { echo " [MINOR] $1"; MINOR=1; } echo "Pre-flight: $DRAFT" echo "------------------------------------" # 1. Format sanity if head -3 "$DRAFT" | grep -q '^---$'; then note_block "Markdown front-matter detected -- storage body must not contain --- fences." fi if grep -qE '\{code:' "$DRAFT"; then note_major "Wiki code-block syntax detected. Use ." fi if grep -qE '\{info:' "$DRAFT" || grep -qE '\{note:' "$DRAFT" || grep -qE '\{warning:' "$DRAFT"; then note_major "Wiki panel syntax detected. Use ." fi if grep -qE '\{plantuml' "$DRAFT"; then if ! grep -qE '." fi fi if grep -qE '^#{1,6} ' "$DRAFT"; then note_major "Markdown heading detected (# / ## / ###). Use

/

/

." fi if grep -qE '^[[:space:]]*```' "$DRAFT"; then note_major "Markdown code fence (\`\`\`) detected. Use ." fi # 2. Secrets / PII SECRET_PATTERNS=( 'AKIA[0-9A-Z]{16}' 'ghp_[A-Za-z0-9]{30,}' 'glpat-[A-Za-z0-9_-]{20,}' 'xox[baprs]-[A-Za-z0-9-]{10,}' 'sk-[A-Za-z0-9]{40,}' 'ATATT[A-Za-z0-9]{30,}' '-----BEGIN [A-Z ]+PRIVATE KEY-----' ) for pat in "${SECRET_PATTERNS[@]}"; do if grep -qE "$pat" "$DRAFT" 2>/dev/null; then note_block "Secret pattern matched: $pat -- scrub before posting." fi done if grep -qE "Netcracker/Projects/NDO/knowledge" "$DRAFT"; then note_block "Body references the local mirror path. Use the public BASS URL." fi # 3. Macro sanity PLANTUML_COUNT=$(grep -cE '/dev/null || echo 0) CODE_COUNT=$(grep -cE '/dev/null || echo 0) if [[ $PLANTUML_COUNT -gt 0 ]]; then if grep -B2 'ac:name="plantuml"' "$DRAFT" | grep -qE '/dev/null 2>&1; then TMPDIR_PRE=$(mktemp -d) awk ' //{flag=0} flag && /<\/ac:plain-text-body>/{capture=0; next} flag && capture{print} ' "$DRAFT" > "$TMPDIR_PRE/all.puml" if [[ -s "$TMPDIR_PRE/all.puml" ]]; then if ! plantuml -tpng -checkonly -failfast2 "$TMPDIR_PRE/all.puml" >/dev/null 2>&1; then note_major "PlantUML syntax check failed. Run plantuml -tpng locally on the extracted body." fi fi rm -rf "$TMPDIR_PRE" fi # 4. Size LINES=$(wc -l < "$DRAFT") if [[ $LINES -gt 300 ]]; then if ! head -5 "$DRAFT" | grep -qiE 'justify|long|expanded'; then note_major "Body is $LINES lines (>300) and no justification header is present." fi fi # 5. Image alt text if grep -qE ' without ac:alt." fi fi echo "------------------------------------" if [[ $BLOCK -eq 1 ]]; then echo "BLOCK -- secret, format, or path issue. Fix and re-run." exit 2 elif [[ $MAJOR -eq 1 ]]; then echo "REVISE -- major issues found. Fix and re-run." exit 1 elif [[ $MINOR -eq 1 ]]; then echo "PASS (with minor notes) -- ready to post." exit 0 else echo "PASS -- ready to post." exit 0 fi