Repository navigation
Well-Known Standards (RFC 9116 + RSR) #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # This workflow is managed by gh actions-lock. | |
| # SPDX-License-Identifier: MPL-2.0 | |
| name: Well-Known Standards (RFC 9116 + RSR) | |
| on: | |
| push: | |
| branches: [main, master] | |
| paths: | |
| - 'www/.well-known/**' | |
| - 'www/tests/**' | |
| - 'www/schemas/**' | |
| - '.well-known/**' # legacy location — migration window (issue #53) | |
| - 'security.txt' | |
| pull_request: | |
| paths: | |
| - 'www/.well-known/**' | |
| - 'www/tests/**' | |
| - 'www/schemas/**' | |
| - '.well-known/**' # legacy location — migration window (issue #53) | |
| schedule: | |
| # Weekly expiry check (Mondays 09:00 UTC) | |
| - cron: '0 9 * * 1' | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| validate: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v7.0.1 | |
| - name: RFC 9116 security.txt validation | |
| run: | | |
| SECTXT="" | |
| if [ -f "www/.well-known/security.txt" ]; then | |
| SECTXT="www/.well-known/security.txt" | |
| elif [ -f ".well-known/security.txt" ]; then | |
| SECTXT=".well-known/security.txt" | |
| echo "::warning::security.txt at legacy root .well-known/ — canonical location is www/.well-known/ (run scripts/migrate-wellknown-to-www.sh)" | |
| elif [ -f "security.txt" ]; then | |
| SECTXT="security.txt" | |
| echo "::warning::security.txt at repository root — canonical location is www/.well-known/ (run scripts/migrate-wellknown-to-www.sh)" | |
| fi | |
| if [ -z "$SECTXT" ]; then | |
| echo "::error::No security.txt found — required for OpenSSF Best Practices. See https://github.com/hyperpolymath/well-known-ecosystem" | |
| exit 1 | |
| fi | |
| # Required: Contact | |
| grep -q "^Contact:" "$SECTXT" || { echo "::error::Missing Contact field"; exit 1; } | |
| # Required: Expires | |
| if ! grep -q "^Expires:" "$SECTXT"; then | |
| echo "::error::Missing Expires field" | |
| exit 1 | |
| fi | |
| # Check expiry | |
| EXPIRES=$(grep "^Expires:" "$SECTXT" | cut -d: -f2- | tr -d ' ' | head -1) | |
| if date -d "$EXPIRES" > /dev/null 2>&1; then | |
| DAYS=$(( ($(date -d "$EXPIRES" +%s) - $(date +%s)) / 86400 )) | |
| if [ $DAYS -lt 0 ]; then | |
| echo "::error::security.txt EXPIRED" | |
| exit 1 | |
| elif [ $DAYS -lt 30 ]; then | |
| echo "::warning::security.txt expires in $DAYS days" | |
| else | |
| echo "✅ security.txt valid ($DAYS days)" | |
| fi | |
| fi | |
| - name: RSR well-known compliance | |
| run: | | |
| MISSING="" | |
| LEGACY="" | |
| for f in security.txt ai.txt humans.txt; do | |
| if [ -f "www/.well-known/$f" ]; then | |
| : | |
| elif [ -f ".well-known/$f" ] || { [ "$f" = security.txt ] && [ -f security.txt ]; }; then | |
| LEGACY="$LEGACY $f" | |
| else | |
| MISSING="$MISSING $f" | |
| fi | |
| done | |
| if [ -n "$LEGACY" ]; then | |
| echo "::warning::legacy .well-known location (canonical is www/.well-known/):$LEGACY — run scripts/migrate-wellknown-to-www.sh" | |
| fi | |
| if [ -n "$MISSING" ]; then | |
| echo "::warning::Missing RSR recommended files:$MISSING" | |
| echo "Reference: https://github.com/hyperpolymath/well-known-ecosystem/.well-known/" | |
| else | |
| echo "✅ RSR well-known compliant" | |
| fi | |
| # Stage 5 (#119) sweeps ~270 repositories. #106 claimed CI "drives the | |
| # migrator"; until now it only printed advice, so nothing verified that a | |
| # repo would actually survive the migration. This step runs the real | |
| # migrator and turns every conflict into an annotation. | |
| # | |
| # --dry-run because this job holds contents: read and cannot push: the | |
| # point is to surface divergence early in the migration window, not to | |
| # mutate a checkout that will be thrown away. The sweep driver | |
| # (scripts/sweep-wellknown.sh) is what performs the real migration. | |
| - name: Legacy root .well-known/ migration report | |
| run: | | |
| if [ ! -d .well-known ]; then | |
| echo "No root .well-known/ — nothing to migrate." | |
| exit 0 | |
| fi | |
| if [ ! -f scripts/migrate-wellknown-to-www.sh ]; then | |
| echo "::warning::root .well-known/ present but no migrator — template is behind #53 stage 5." | |
| exit 0 | |
| fi | |
| bash scripts/migrate-wellknown-to-www.sh --dry-run --report wellknown-migration.tsv | |
| echo "--- planned migration ---" | |
| cat wellknown-migration.tsv | |
| # Conflicts are warnings, not errors, for the duration of the | |
| # migration window (#106): a repo must not go red for a condition | |
| # the sweep exists to fix. It must not be silent either. | |
| while IFS=$'\t' read -r action path detail; do | |
| case "$action" in | |
| quarantined|conflict|left) | |
| echo "::warning title=well-known migration::$action $path — $detail" | |
| ;; | |
| esac | |
| done < <(tail -n +2 wellknown-migration.tsv) | |
| - name: www bundle self-test | |
| run: | | |
| if [ -d www/tests ]; then | |
| bash www/tests/run-all.sh | |
| else | |
| echo "www/tests absent — site-operations bundle not present; skipping." | |
| fi | |
| - name: Mixed content check | |
| run: | | |
| MIXED=$(grep -rE 'src="http://|href="http://' --include="*.html" --include="*.htm" . 2>/dev/null | grep -vE 'localhost|127\.0\.0\.1|example\.com' | head -5 || true) | |
| if [ -n "$MIXED" ]; then | |
| echo "::error::Mixed content (HTTP in HTML)" | |
| echo "$MIXED" | |
| exit 1 | |
| fi | |
| echo "✅ No mixed content" | |
| - name: DNS security records check | |
| if: hashFiles('CNAME') != '' | |
| run: | | |
| DOMAIN=$(cat CNAME 2>/dev/null | tr -d '\n') | |
| if [ -n "$DOMAIN" ]; then | |
| echo "Checking DNS for $DOMAIN..." | |
| # CAA record | |
| dig +short CAA "$DOMAIN" | grep -q "issue" && echo "✅ CAA record" || echo "::warning::No CAA record" | |
| # DNSSEC | |
| dig +dnssec +short "$DOMAIN" | grep -q "RRSIG" && echo "✅ DNSSEC" || echo "::warning::No DNSSEC" | |
| fi |