diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 1c4d465..6f74071 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -45,12 +45,7 @@ jobs:
run: hugo --gc --minify --baseURL "https://tiennm99.github.io/tsuki/"
- name: Build Pagefind index
- run: |
- if find exampleSite/public -name "*.html" -type f | head -1 | grep -q .; then
- npx pagefind --site exampleSite/public
- else
- echo "No HTML files found yet (layouts not implemented). Skipping Pagefind."
- fi
+ run: npx pagefind --site exampleSite/public
- name: Assert CSS bundle budget (≤ 4200 B gz)
run: |
@@ -70,8 +65,8 @@ jobs:
run: ./scripts/smoke-tests.sh exampleSite/public
- name: htmltest (broken internal links + HTML5 validation)
- # TODO before v0.2.0 tag: pin @master to a commit SHA (supply-chain hygiene).
- uses: wjdp/htmltest-action@master
+ # Pinned to master SHA (2026-05-10) for supply-chain hygiene. Refresh periodically.
+ uses: wjdp/htmltest-action@31be84a95c860a331e0cf9a99f71e3eb39d2f86b
with:
config: .htmltest.yml
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 95efe60..a6a5f3f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,27 @@ All notable changes to tsuki will be documented here. Format follows [Keep a Cha
## [Unreleased]
+## [0.2.1] — 2026-05-10
+
+Patch release. Closes 5 P1 correctness/security findings from the post-v0.2.0 review plus 2 CI hygiene items. No new features.
+
+### Security
+
+- **Render-link no longer trusts inline HTML in link text** — `layouts/_markup/render-link.html` dropped `| safeHTML` on `.Text`. With Goldmark `unsafe: true`, the prior pipeline allowed `[
](url)` inner-text to execute. Side effect: italic/emphasis-in-link (`[*x*](url)`) now renders as plain text rather than ``. Restore by overriding the render hook if needed. Self-XSS in single-author themes; consistency fix vs `render-image.html`.
+- **Project links sanitize URL + add `noreferrer`** — `layouts/_partials/home/projects.html` pipes `repo`/`demo` URLs through `safeURL` and emits `rel="noopener noreferrer" target="_blank"`. Closes inconsistency with the `render-link` policy and prevents referer leakage to project destinations.
+- **Comments gate tightened** — `layouts/_partials/comments.html` now requires `repo`, `repoId`, AND `categoryId` in addition to `enable`. Prevents broken Giscus iframes when partially configured.
+- **htmltest GitHub Action pinned to commit SHA** — `.github/workflows/pages.yml` no longer tracks `wjdp/htmltest-action@master`; pinned to `31be84a` for supply-chain hygiene.
+
+### Fixed
+
+- **`seo.html` `$authorURL` chain hardened** — refactored fragile `site.Params.profile.url | default ...` chain into nil-safe `with` blocks. Site builds no longer risk `nil.url` template error when consumers follow the documented `data/profile.yaml`-only configuration.
+- **Header navigation respects sub-path deploys** — `layouts/_partials/nav.html` pipes `Menu.URL` through `relURL`. Sites deploying under a sub-path (e.g., GitHub Pages `/repo/`) with `url:`-form menu entries now route correctly.
+- **CI Pagefind step simplified** — `.github/workflows/pages.yml` dropped the dead `if find ... | head -1 | grep -q .` guard. Layouts exist; the else branch never triggered.
+
+## [0.2.0] — 2026-05-09
+
+SEO baseline, accessibility polish, author UX, discovery, distribution prep, CI hardening. See [v0.2.0 tag](https://github.com/tiennm99/tsuki/releases/tag/v0.2.0) for highlights.
+
### Changed
- **TOC gate consolidated** to `_partials/toc-enabled.html` — single source for the `params.toc.{enable,minWordCount}` + per-page `toc: false` predicate, called from `single.html` (TOC partial) and `_partials/footer.html` (toc-active.js loader). Was duplicated 6-line logic in two sites; now one partial. No behavior change.
diff --git a/layouts/_markup/render-link.html b/layouts/_markup/render-link.html
index 7b58237..db8b858 100644
--- a/layouts/_markup/render-link.html
+++ b/layouts/_markup/render-link.html
@@ -7,5 +7,5 @@
{{ .Text | safeHTML }}
+>{{ .Text }}
{{- /**/ -}}
diff --git a/layouts/_partials/comments.html b/layouts/_partials/comments.html
index 9e736ec..619a1ab 100644
--- a/layouts/_partials/comments.html
+++ b/layouts/_partials/comments.html
@@ -1,5 +1,5 @@
{{- $g := site.Params.comments.giscus -}}
-{{- if and $g $g.enable -}}
+{{- if and $g $g.enable $g.repo $g.repoId $g.categoryId -}}
{{- if ne .Params.comments false -}}
{{ i18n "comments" | default "Bình luận" }}
diff --git a/layouts/_partials/head/seo.html b/layouts/_partials/head/seo.html index 97741ed..0259a70 100644 --- a/layouts/_partials/head/seo.html +++ b/layouts/_partials/head/seo.html @@ -61,7 +61,10 @@ {{- /* JSON-LD Article — only on single posts (IsPage + Kind page). */ -}} {{- if and .IsPage (eq .Kind "page") -}} {{- $authorName := site.Params.author | default (and site.Data.profile site.Data.profile.name) | default site.Title -}} -{{- $authorURL := site.Params.profile.url | default (and site.Data.profile site.Data.profile.url) | default site.Home.Permalink -}} +{{- $authorURL := "" -}} +{{- with site.Params.profile -}}{{- $authorURL = .url -}}{{- end -}} +{{- if not $authorURL -}}{{- with site.Data.profile -}}{{- $authorURL = .url -}}{{- end -}}{{- end -}} +{{- if not $authorURL -}}{{- $authorURL = site.Home.Permalink -}}{{- end -}} {{- $keywords := slice -}} {{- range .GetTerms "tags" -}}{{- $keywords = $keywords | append .LinkTitle -}}{{- end -}} {{- $publisher := dict "@type" "Organization" "name" site.Title -}} diff --git a/layouts/_partials/home/projects.html b/layouts/_partials/home/projects.html index 90b9fb1..2da9e8d 100644 --- a/layouts/_partials/home/projects.html +++ b/layouts/_partials/home/projects.html @@ -27,10 +27,10 @@{{- with $project.repo }} -- repo →
+ - repo →
{{- end }}
{{- with $project.demo }}
- - demo →
+ - demo →
{{- end }}
diff --git a/layouts/_partials/nav.html b/layouts/_partials/nav.html index a46b7b9..a054968 100644 --- a/layouts/_partials/nav.html +++ b/layouts/_partials/nav.html @@ -3,7 +3,7 @@ {{- range site.Menus.main }} {{- $current := or ($.IsMenuCurrent "main" .) ($.HasMenuCurrent "main" .) }}