This document describes the link validation tools available for the GraphGRC documentation system.
The GraphGRC documentation contains thousands of interconnected markdown files with links between controls, frameworks, policies, and standards. To ensure documentation quality, we provide automated tools to validate and fix broken links.
- Total links: 4,860
- Valid links: 4,689 (96.5%)
- Broken links: 171 (3.5%)
The remaining broken links fall into these categories:
- Template placeholders (24) -
../custom/control-id.md- intentional placeholders in templates - Missing framework controls (147) - references to controls not yet generated (ISO 27701, some GDPR articles, SOC 2 PI controls)
Validates all markdown links in the docs/ directory.
make validate-linksOutput:
- Summary of total links, valid links, and broken links
- Detailed list of each broken link with file location and line number
- Exit code 1 if any broken links are found (useful for CI/CD)
Use cases:
- Pre-deployment validation
- CI/CD pipeline integration
- Regular documentation health checks
Automatically fixes broken links by finding the correct paths.
make fix-linksWhat it fixes:
- Framework links (SOC 2, GDPR, ISO, NIST, SCF)
- Custom control references
- Cross-directory links
- Relative path corrections
What it doesn't fix:
- Links to non-existent files
- Placeholder/template links
- External URLs
Output:
- List of files modified
- Count of links fixed per file
- Summary of total fixes
Removes build artifacts and temporary files.
make cleanRemoves:
bin/directory (compiled binaries)*.tmpfiles in docs/
Features:
- Recursively scans all markdown files in a directory
- Extracts markdown links using regex:
[text](path) - Validates that target files/directories exist
- Skips external links (http://, https://, mailto:)
- Skips anchor-only links (#section)
- Reports line numbers for debugging
Algorithm:
- Walk directory tree
- For each
.mdfile:- Parse all markdown links
- Resolve relative paths
- Check if target exists
- Report broken links
Features:
- Automatically corrects common link pattern errors
- Handles framework-specific link patterns
- Preserves anchors (#section references)
- Uses pattern matching to identify control types
Link patterns recognized:
| Pattern | Type | Example | Fixed Path |
|---|---|---|---|
cc*.md |
SOC 2 | cc61.md |
frameworks/soc2/cc61.md |
art*.md |
GDPR | art32.md |
frameworks/gdpr/art32.md |
a-*.md |
ISO 27002 | a-5.md |
frameworks/iso27002/a-5.md |
\d+.md |
ISO 27001 | 7.md |
frameworks/iso27001/7.md |
[a-z]{2}-\d+.md |
NIST | ac-2.md |
frameworks/nist80053/ac-2.md |
[a-z]{3}-\d{2}.md |
Custom | acc-01.md |
custom/acc-01.md |
[a-z]{3}-\d+*.md |
SCF | gov-01.md |
frameworks/scf/gov-01-*.md |
Algorithm:
- Read file content
- Find all markdown links
- For each link:
- Skip if external or anchor-only
- Check if target exists
- If not, try pattern matching
- Replace with correct path
- Write updated content if changes made
Add to your GitHub Actions workflow:
name: Validate Documentation Links
on:
push:
paths:
- 'docs/**/*.md'
pull_request:
paths:
- 'docs/**/*.md'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Validate links
run: make validate-linksProblem: Custom controls link to framework controls without full path
[CC6.1](cc61.md)Fixed to:
[CC6.1](frameworks/soc2/cc61.md)Problem: Links use short names but files have long descriptive names
[GOV-01](gov-01.md)Fixed to:
[GOV-01](frameworks/scf/gov-01-cybersecurity&dataprotectiongovernanceprogram.md)Problem: Framework files link to other frameworks without relative path
[Article 32](art32.md)Fixed to:
[Article 32](../gdpr/art32.md)Problem: SCF files link to ISO controls by number only
[7.4.a](7.md#74a)Fixed to:
[7.4.a](../iso27001/7.md#74a)The following link types cannot be automatically fixed:
- Template placeholders:
../custom/control-id.md- intentional placeholders - Missing controls: References to controls not yet generated
- Typos in link text: Validator can't detect semantic errors
Some framework controls referenced in SCF mappings don't have generated markdown files:
- SOC 2 PI controls: PI1.1, PI1.2, PI1.4, PI1.5
- GDPR articles: Article 43 and others
- ISO 27701: P5.2, P5.1, P4.3, C1.1, C1.2
These would need to be added to the documentation generation process in src/main.go.
# Build validator
make build-validator
# Build fixer
make build-fixer
# Run directly
./bin/validate-links docs/
./bin/fix-links docs/To add support for new framework link patterns:
- Edit
src/cmd/fix-links/main.go - Add pattern detection in
tryFixFrameworkLink() - Add helper function if needed (like
isNISTControl()) - Test with sample files
Example:
} else if strings.HasPrefix(filename, "pci-") {
// PCI DSS control
frameworkPaths = []string{
"frameworks/pcidss/" + filename,
}
}- Check if the file actually exists at the reported path
- Verify the link syntax is correct:
[text](path) - Ensure paths use forward slashes, not backslashes
- Check if the target file actually exists
- Verify the link pattern is recognized (see table above)
- Run validator after fixer to see remaining issues
- The tools process all files in memory
- For very large documentation (>10,000 files), consider:
- Running on subdirectories
- Increasing system memory limits
- Parallelizing file processing
Potential improvements:
- Parallel processing - Process files concurrently for speed
- Incremental validation - Only check changed files in git
- Anchor validation - Verify that
#sectionanchors exist - External link checking - Validate HTTP/HTTPS links (with caching)
- Auto-fix on commit - Git pre-commit hook integration
- Link suggestion - Fuzzy matching for typos
- Report formats - JSON, HTML, or markdown output