Skip to content

Switch to self-hosted runner #166

Switch to self-hosted runner

Switch to self-hosted runner #166

Workflow file for this run

name: Lint
on:
push:
branches: [main]
paths-ignore: ['**.md', 'docs/**', 'LICENSE', '.gitignore']
pull_request:
branches: [main]
paths-ignore: ['**.md', 'docs/**', 'LICENSE', '.gitignore']
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Run ShellCheck on all scripts
uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # 2.0.0
with:
scandir: scripts
severity: warning
actionlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install actionlint
run: |
ACTIONLINT_VERSION=1.7.7
curl -sSfL "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" \
| tar xz -C /usr/local/bin actionlint
- name: Run actionlint
run: actionlint -color
gitleaks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
- name: Install gitleaks
run: |
GITLEAKS_VERSION=8.21.2
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
| tar xz -C /usr/local/bin gitleaks
- name: Run gitleaks
run: gitleaks detect --source . --verbose
no-personal-data:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Check for personal paths or data leaks
run: |
echo "Scanning for personal data in scripts and docs..."
FAIL=0
# Check for common personal path patterns
if grep -rn '/mnt/user\|/home/[a-z]' scripts/ docs/ 2>/dev/null; then
echo "FAIL: Found personal paths in scripts/docs"
FAIL=1
fi
# Check for hardcoded hostnames
if grep -rn 'watchtower\|geiserback\|ts\.net' scripts/ docs/ 2>/dev/null; then
echo "FAIL: Found hardcoded hostnames"
FAIL=1
fi
# Check for hardcoded sample names (but allow 'your_name' placeholders)
if grep -rn 'SAMPLE=sergio\|SAMPLE=annais' scripts/ docs/ 2>/dev/null; then
echo "FAIL: Found hardcoded sample names"
FAIL=1
fi
if [ "$FAIL" -eq 1 ]; then
exit 1
fi
echo "OK: No personal data found"
markdown-links:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Check for broken internal links
run: |
echo "Checking internal markdown links..."
rm -f /tmp/link_fail
for md in docs/*.md README.md; do
# Extract markdown links: [text](target)
grep -oP '\]\([^)]+\)' "$md" 2>/dev/null | \
grep -oP '\(([^)]+)\)' | tr -d '()' | \
grep -v '^http' | grep -v '^#' | \
while read -r link; do
file=$(echo "$link" | cut -d'#' -f1)
if [ -n "$file" ]; then
dir=$(dirname "$md")
target="${dir}/${file}"
if [ ! -f "$target" ]; then
echo "BROKEN: ${md} -> ${link} (file not found: ${target})"
echo "1" > /tmp/link_fail
fi
fi
done
done
if [ -f /tmp/link_fail ]; then
exit 1
fi
echo "OK: All internal links valid"
version-consistency:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Verify Docker image tags are consistent across scripts and docs
run: |
echo "Checking Docker image tags across versions.env, scripts, and docs..."
FAIL=0
# Parse versions.env: extract image_name:tag pairs
while IFS='=' read -r var value; do
# Skip comments and empty lines
[[ "$var" =~ ^#.*$ || -z "$var" ]] && continue
# Strip quotes and inline comments
image=$(echo "$value" | tr -d '"' | sed 's/#.*//' | xargs)
# Split into base name and tag
base="${image%%:*}"
tag="${image##*:}"
[ "$base" = "$tag" ] && continue # no tag found
# Check all scripts that reference this base image
for f in scripts/*.sh; do
# Scripts that source versions.env use image variables — skip
if grep -qF 'versions.env' "$f"; then
continue
fi
# Check for hardcoded references with wrong tag
if grep -qF "${base}:" "$f" 2>/dev/null; then
if ! grep -qF "${base}:${tag}" "$f"; then
echo "FAIL: ${f} references ${base} but not with tag ${tag}"
FAIL=1
fi
fi
done
# Check docs that reference this base image (skip :latest-only images)
[ "$tag" = "latest" ] && continue
# Version prefix without build hash (e.g. 1.6.0 from 1.6.0--h9ee0642_2)
vtag="${tag%%--*}"
# Extract the short name (last segment) for matching in docs
short="${base##*/}"
for f in docs/*.md README.md CONTRIBUTING.md; do
[ -f "$f" ] || continue
# Skip files with intentionally historical/failed image tags
case "$f" in docs/lessons-learned.md|docs/troubleshooting.md) continue ;; esac
if grep -qF "$short" "$f" 2>/dev/null; then
# Doc references this image — check for stale tags
# Accept both full tag (1.6.0--hash) and display prefix (1.6.0)
stale=$(grep -oP "${base}:\K[^\s\`\"\\\\)>]+" "$f" 2>/dev/null | grep -vF "$tag" | grep -vF "$vtag" | head -1)
if [ -n "$stale" ]; then
echo "FAIL: ${f} has stale tag ${base}:${stale} (expected :${tag})"
FAIL=1
fi
fi
done
done < versions.env
if [ "$FAIL" -eq 0 ]; then
echo "OK: All Docker image tags are consistent"
fi
exit "$FAIL"