# === Hugo: publish Markdown & sign with OpenPGP; add Download & Verify block === SHELL := /bin/bash # --- Config --- KEYID ?= 55A2A5DE84792BACC6CAEE3FB5882850E04C8D2A # or use your email: iman.alip2001@gmail.com CONTENT_DIR ?= content INCLUDE_DIRS ?= posts PhD_journey PUBLISH_DIR ?= static/sources MODE ?= interactive # interactive | loopback # Find helper: $(call MD_FIND,) MD_FIND = find $(1) -type f -name '*.md' -print0 .PHONY: verify-ready publish-md sign-md append-sigdl sigdl-shortcode publish-and-sign sign-content clean-published clean-signatures # === One-command flow (matches your "Build flow end to end") === verify-ready: sigdl-shortcode publish-md sign-md append-sigdl @echo "โœ… Done: published, signed, and appended {{< sigdl >}} to posts." # 1) Copy raw Markdown to static/sources so readers can download exact bytes. publish-md: @set -euo pipefail; \ for sub in $(INCLUDE_DIRS); do \ root="$(CONTENT_DIR)/$$sub"; \ if [[ -d "$$root" ]]; then \ $(call MD_FIND,$$root) | while IFS= read -r -d '' md; do \ rel="$${md#$(CONTENT_DIR)/}"; \ out="$(PUBLISH_DIR)/$$rel"; \ mkdir -p "$$(dirname "$$out")"; \ cp -f -- "$$md" "$$out"; \ echo "published: $$out"; \ done; \ else \ echo "skip missing: $$root"; \ fi; \ done # 2) Sign the published Markdown (recommended target for readers to verify). sign-md: publish-md @set -euo pipefail; \ # Set up interactive pinentry if needed if [[ "$(MODE)" == "interactive" ]]; then \ if tty >/dev/null 2>&1; then export GPG_TTY="$$(tty)"; fi; \ fi; \ # Require passphrase in env for loopback mode if [[ "$(MODE)" == "loopback" ]] && [[ -z "$${GPG_PASSPHRASE:-}" ]]; then \ echo "ERROR: MODE=loopback but GPG_PASSPHRASE not set"; exit 1; \ fi; \ $(call MD_FIND,$(PUBLISH_DIR)) | while IFS= read -r -d '' f; do \ asc="$$f.asc"; \ echo "sign: $$f -> $$asc"; \ if [[ "$(MODE)" == "loopback" ]]; then \ printf "%s" "$$GPG_PASSPHRASE" | gpg --yes --pinentry-mode loopback --passphrase-fd 0 \ --local-user $(KEYID) --detach-sign --armor -o "$$asc" "$$f"; \ else \ gpg --yes --local-user $(KEYID) --detach-sign --armor -o "$$asc" "$$f"; \ fi; \ done # Convenience alias (kept for compatibility) publish-and-sign: sign-md # 3) Ensure the shortcode file exists (created once if missing) โ€” heredoc-free, make-safe. sigdl-shortcode: @set -euo pipefail; \ path="layouts/shortcodes/sigdl.html"; \ if [[ ! -f "$$path" ]]; then \ echo "creating $$path"; \ mkdir -p "$$(dirname "$$path")"; \ printf '%s\n' \ '{{- /* sigdl โ€” Download & Verify block for each post.' \ ' Assumes you publish .md to /static/sources/.md and sign to .md.asc.' \ ' Usage in post: {{< sigdl >}} */ -}}' \ '{{- $$rel := replace .Page.File.Path "content/" "" -}}' \ '{{- $$download := printf "/sources/%s" $$rel -}}' \ '{{- $$asc := printf "%s.asc" $$download -}}' \ '{{- $$staticAscPath := printf "static%s.asc" $$download -}}' \ '{{- $$sig := "" -}}' \ '{{- if (fileExists $$staticAscPath) -}}' \ ' {{- $$sig = (readFile $$staticAscPath) | htmlEscape -}}' \ '{{- end -}}' \ '
' \ '

Downloads:' \ ' Markdown ยท' \ ' Signature (.asc)' \ '

' \ ' {{- if $$sig -}}' \ '
' \ ' View signature' \ '
{{$$sig}}
' \ '
' \ ' {{- end -}}' \ '

Verify locally:

' \ '
' \
'curl -O {{ $$download | absURL }}' \
'curl -O {{ $$asc | absURL }}' \
'gpg --verify {{ path.Base $$asc }} {{ path.Base $$download }}' \
'  
' \ '
' \ > "$$path"; \ else \ echo "exists: $$path"; \ fi # 4) Append the shortcode to posts (idempotent). append-sigdl: @set -euo pipefail; \ for sub in $(INCLUDE_DIRS); do \ root="$(CONTENT_DIR)/$$sub"; \ [[ -d "$$root" ]] || { echo "skip missing: $$root"; continue; }; \ $(call MD_FIND,$$root) | while IFS= read -r -d '' md; do \ if grep -q '{{< *sigdl' "$$md"; then \ echo "exists: $$md"; \ else \ printf "\n\n---\n\n{{< sigdl >}}\n" >> "$$md"; \ echo "appended: $$md"; \ fi; \ done; \ done # (Optional) Sign files directly under content/ (useful for your own archive; readers should prefer the published copies) sign-content: @set -euo pipefail; \ if [[ "$(MODE)" == "interactive" ]]; then \ if tty >/dev/null 2>&1; then export GPG_TTY="$$(tty)"; fi; \ fi; \ if [[ "$(MODE)" == "loopback" ]] && [[ -z "$${GPG_PASSPHRASE:-}" ]]; then \ echo "ERROR: MODE=loopback but GPG_PASSPHRASE not set"; exit 1; \ fi; \ for sub in $(INCLUDE_DIRS); do \ root="$(CONTENT_DIR)/$$sub"; \ [[ -d "$$root" ]] || continue; \ $(call MD_FIND,$$root) | while IFS= read -r -d '' f; do \ asc="$$f.asc"; \ echo "sign: $$f -> $$asc"; \ if [[ "$(MODE)" == "loopback" ]]; then \ printf "%s" "$$GPG_PASSPHRASE" | gpg --yes --pinentry-mode loopback --passphrase-fd 0 \ --local-user $(KEYID) --detach-sign --armor -o "$$asc" "$$f"; \ else \ gpg --yes --local-user $(KEYID) --detach-sign --armor -o "$$asc" "$$f"; \ fi; \ done; \ done # Cleanup helpers clean-published: @echo "rm -rf $(PUBLISH_DIR)"; rm -rf -- "$(PUBLISH_DIR)" clean-signatures: @set -euo pipefail; \ find "$(PUBLISH_DIR)" -type f -name '*.md.asc' -delete 2>/dev/null || true; \ find "$(CONTENT_DIR)" -type f -name '*.md.asc' -delete 2>/dev/null || true # --- Cleanup: remove old {{< sig ... >}} blocks so only {{< sigdl >}} remains --- .ONESHELL: .PHONY: remove-old-sig disable-old-sig-shortcode # Delete any line that contains the legacy {{< sig ... >}} shortcode (but not {{< sigdl >}}) remove-old-sig: @set -euo pipefail for sub in $(INCLUDE_DIRS); do root="$(CONTENT_DIR)/$$sub" [[ -d "$$root" ]] || { echo "skip missing: $$root"; continue; } find "$$root" -type f -name '*.md' -print0 | while IFS= read -r -d '' f; do if grep -Eq '\{\{<\s*sig(\s|>)' "$$f"; then sed -E -i '/\{\{<\s*sig(\s|>)/d' "$$f" echo "removed old sig: $$f" fi done done # Disable the old layouts/shortcodes/sig.html so it can't render accidentally disable-old-sig-shortcode: @set -euo pipefail path="layouts/shortcodes/sig.html" if [[ -f "$$path" ]]; then mv "$$path" "$$path.bak" echo "moved $$path -> $$path.bak (legacy shortcode disabled)" else echo "no legacy shortcode found at $$path" fi