This guide explains the automated checks that run on your content before it merges.
One git hook (.githooks/pre-commit, enabled by ./setup-hooks.sh) runs on
every commit and does two things:
- Stamps content dates. It adds
dateandlastmodto new content files and refresheslastmodon edited ones, then re-stages the file into your commit. This stays a native git hook because the pre-commit framework doesn't re-stage files, and a "now" timestamp would never pass a CI idempotency check. - Runs the pre-commit framework
(
.pre-commit-config.yaml) for linting, secret scanning, tag validation, spell checking, and SCSS/stylelint. The same framework runs as a required check on pull requests, where it lints only the files a pull request changes.
Because ./setup-hooks.sh sets core.hooksPath=.githooks, git runs this hook
and ignores anything in .git/hooks. You don't run pre-commit install: the
hook calls the framework for you, so one setup covers everything.
- New files: Adds
dateandlastmodfields with the current timestamp - Modified files: Refreshes the
lastmodfield - Format: ISO 8601 with UTC timezone, for example
2025-01-16T10:30:45+00:00 - You don't add or update these fields yourself
These fail the commit, and the required CI check, when they find a problem:
- Code and content linting: JavaScript (
eslint), Markdown (markdownlint), SCSS (stylelint), and Python (bandit,black) - Security and hygiene: secret scanning (
gitleaks), private-key detection, large-file checks, and whitespace, end-of-file, and line-ending fixes - GitHub Actions: workflow security (
zizmor) and linting (actionlint)
Each linter reads the repository's own configuration, for example
.stylelintrc.json for SCSS and .markdownlint-cli2.jsonc for Markdown.
The SCSS lint step runs the project's own stylelint from node_modules, so it
needs npm install (see Setting up). The other linters use
pre-commit-managed environments and need nothing more.
- Checks that tags match the approved taxonomy, stay within five per article, and use the expected capitalization
- Reports problems as warnings but never blocks a commit
- Catches typos and misspellings; reports but never blocks a commit
- Runs locally only; the CI check skips it (
SKIP=content-spellcheck) - Ignores code blocks, Hugo shortcodes (for example
{{< youtube >}}), inline code, and URLs - Uses a custom dictionary for technical terms (
.aspell.en.pws)
Do this once per clone:
-
Install the pre-commit framework:
brew install pre-commit # or: pipx install pre-commit -
Enable the git hook:
./setup-hooks.sh
-
Install Node dependencies if you edit SCSS (
assets/scss/), so the stylelint hook can run:npm install
-
Optional: install aspell so the local spell check runs:
# macOS brew install aspell # Ubuntu/Debian sudo apt install aspell # RHEL/CentOS/Fedora sudo dnf install aspell # Alpine Linux apk add aspell # Arch Linux sudo pacman -S aspell
Every commit now stamps content dates and runs the framework checks. If you
commit before installing the pre-commit framework, the hook still stamps dates
and prints a reminder to install it.
When you run git commit, the hook prints its date-stamp result first, then the
pre-commit framework's per-hook results.
📅 Updated lastmod on 1 file(s):
- content/chainguard/chainguard-images/getting-started.md
trim trailing whitespace.................................................Passed
fix end of files.........................................................Passed
Detect hardcoded secrets.................................................Passed
markdownlint-cli2........................................................Passed
Validate content tags....................................................Passed
A blocking hook (a linter, a secret scan, or a file-hygiene check) prints the failure and stops the commit. Fix the reported issue, stage the change, and commit again:
markdownlint-cli2........................................................Failed
- hook id: markdownlint-cli2
- exit code: 1
content/chainguard/tutorial.md:14 MD012/no-multiple-blanks Multiple consecutive blank lines
Some hooks fix the file for you (for example, trailing-whitespace and end-of-file-fixer) and then fail so you can review and re-stage the change.
Tag and spelling checks print warnings but don't stop the commit:
Validate content tags....................................................Passed
⚠️ Tag not in approved list: 'NewTag'
When creating a new article, you no longer need to add date fields manually. Just focus on your content:
What you write:
---
title: "Getting Started with Chainguard Images"
description: "Learn how to use Chainguard's secure container images"
tags: ["Chainguard Containers", "Getting Started", "Overview"]
---What gets committed (automatically):
---
title: "Getting Started with Chainguard Images"
date: 2025-01-16T10:30:45+00:00
lastmod: 2025-01-16T10:30:45+00:00
description: "Learn how to use Chainguard's secure container images"
tags: ["Chainguard Containers", "Getting Started", "Overview"]
---When you modify an article, the lastmod field is automatically updated:
Before your edit:
---
title: "Security Best Practices"
date: 2024-12-01T09:00:00+00:00
lastmod: 2024-12-15T14:30:00+00:00
---After commit (automatic update):
---
title: "Security Best Practices"
date: 2024-12-01T09:00:00+00:00
lastmod: 2025-01-16T10:45:30+00:00
---If you see a tag warning, update your frontmatter so the tag matches the approved taxonomy:
# ❌ Wrong
tags: ["chainguard containers", "OVERVIEW"]
# ✅ Correct
tags: ["Chainguard Containers", "Overview"]The spell checker might flag technical terms as errors. You have three options:
-
Fix actual typos:
recieve→receiveconfiguation→configuration
-
Add technical terms to the dictionary: If you're using a legitimate technical term that's flagged:
echo "MyTechnicalTerm" >> .aspell.en.pws
-
Skip the check (use sparingly):
git commit --no-verify -m "Your commit message"
Product Tags:
Chainguard ContainersChainguard Librarieschainctl
Content Types:
Overview- High-level introductionsProcedural- Step-by-step guidesConceptual- Theory/backgroundReference- API/command docsFAQ- Common questions
Action Tags:
Getting StartedMigrationConfigurationTroubleshootingIntegration
Platform Tags:
AWS,GCP,AzureKubernetesDocker HubGitHub,GitLab
For the complete list, see TAG_GUIDELINES.md.
Install aspell using your system's package manager:
# macOS
brew install aspell
# Ubuntu/Debian
sudo apt install aspell
# RHEL/CentOS/Fedora
sudo yum install aspell
# Alpine Linux
apk add aspell
# Arch Linux
sudo pacman -S aspellMake sure hooks are enabled:
git config core.hooksPath
# Should output: .githooksIf not, run:
./setup-hooks.shFor urgent commits where you need to bypass the check:
git commit --no-verify -m "Emergency fix"Note: Use this sparingly and fix any issues in a follow-up commit.
git config --unset core.hooksPath- Let automation handle dates: Never manually add or update
date/lastmodfields - the hook does this for you - Run checks early: Stage your files and run
git commiteven before writing a message to see if there are issues - Fix issues promptly: Don't use
--no-verifyas a habit - Keep tags minimal: Use 3-4 tags that truly describe the content
- Review spelling suggestions: The spell checker helps maintain professional documentation
- Use code blocks properly: Put commands and code in markdown code blocks (```) to avoid spelling false positives
- For tag questions: Review TAG_GUIDELINES.md
- For hook issues: Check with the engineering team
- For adding new approved tags: Submit a PR with justification
Remember: The hook is here to help maintain quality and consistency. It catches issues early, saving time in review and ensuring a better experience for our readers!