From e6a0f25b44e98edb82b26f3bfb6139f46466a4ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:30:40 -0400 Subject: [PATCH 1/7] Bump the minor-and-patch group with 2 updates (#51) Bumps the minor-and-patch group with 2 updates: [ruby/setup-ruby](https://github.com/ruby/setup-ruby) and [anthropics/claude-code-action](https://github.com/anthropics/claude-code-action). Updates `ruby/setup-ruby` from 1.310.0 to 1.312.0 - [Release notes](https://github.com/ruby/setup-ruby/releases) - [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb) - [Commits](https://github.com/ruby/setup-ruby/compare/afeafc3d1ab54a631816aba4c914a0081c12ff2f...12fd324f1d0b43274fdc8130f6980590a667c455) Updates `anthropics/claude-code-action` from 1.0.137 to 1.0.144 - [Release notes](https://github.com/anthropics/claude-code-action/releases) - [Commits](https://github.com/anthropics/claude-code-action/compare/41ea7642c1436fa0ee57aae58347904b71a5af27...0f97b95b6536c26e5f6bd90faec370d41695beca) --- updated-dependencies: - dependency-name: ruby/setup-ruby dependency-version: 1.312.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: anthropics/claude-code-action dependency-version: 1.0.144 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: minor-and-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/cd-mobile-ios.yaml | 2 +- .github/workflows/compliance-audit.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cd-mobile-ios.yaml b/.github/workflows/cd-mobile-ios.yaml index 90ad74a..4a1285a 100644 --- a/.github/workflows/cd-mobile-ios.yaml +++ b/.github/workflows/cd-mobile-ios.yaml @@ -73,7 +73,7 @@ jobs: cache: npm cache-dependency-path: ${{ inputs.cache-dependency-path }} - - uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1 + - uses: ruby/setup-ruby@12fd324f1d0b43274fdc8130f6980590a667c455 # v1 with: ruby-version: ${{ inputs.ruby-version }} bundler-cache: true diff --git a/.github/workflows/compliance-audit.yaml b/.github/workflows/compliance-audit.yaml index 20754a5..96c4409 100644 --- a/.github/workflows/compliance-audit.yaml +++ b/.github/workflows/compliance-audit.yaml @@ -76,7 +76,7 @@ jobs: - name: Run compliance audit id: audit - uses: anthropics/claude-code-action@41ea7642c1436fa0ee57aae58347904b71a5af27 # v1 + uses: anthropics/claude-code-action@0f97b95b6536c26e5f6bd90faec370d41695beca # v1 with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} prompt: | From 0200ef1f3845f7df4407ff3a2c9c44ae8980ae0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:30:44 -0400 Subject: [PATCH 2/7] Bump actions/setup-node from 4 to 6 (#52) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v4...v6) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/cd-cdk.yaml | 2 +- .github/workflows/cd-mobile-ios.yaml | 2 +- .github/workflows/ci-python-sam.yaml | 2 +- .github/workflows/ci-typescript-cdk.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cd-cdk.yaml b/.github/workflows/cd-cdk.yaml index 8bdce3c..9fc541d 100644 --- a/.github/workflows/cd-cdk.yaml +++ b/.github/workflows/cd-cdk.yaml @@ -67,7 +67,7 @@ jobs: if: ${{ inputs.dotnet-publish-project != '' }} run: dotnet publish ${{ inputs.dotnet-publish-project }} --configuration Release --runtime linux-arm64 --self-contained false --output $(dirname ${{ inputs.dotnet-publish-project }})/bin/Release/net8.0/linux-arm64/publish - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 with: node-version: ${{ inputs.node-version }} diff --git a/.github/workflows/cd-mobile-ios.yaml b/.github/workflows/cd-mobile-ios.yaml index 4a1285a..4a808f7 100644 --- a/.github/workflows/cd-mobile-ios.yaml +++ b/.github/workflows/cd-mobile-ios.yaml @@ -67,7 +67,7 @@ jobs: role-to-assume: ${{ secrets.deploy-role-arn }} aws-region: ${{ inputs.region }} - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 with: node-version: ${{ inputs.node-version }} cache: npm diff --git a/.github/workflows/ci-python-sam.yaml b/.github/workflows/ci-python-sam.yaml index 2e0c019..b15192e 100644 --- a/.github/workflows/ci-python-sam.yaml +++ b/.github/workflows/ci-python-sam.yaml @@ -83,7 +83,7 @@ jobs: - name: Setup Node.js if: ${{ inputs.run-cdk-synth }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: ${{ inputs.node-version }} diff --git a/.github/workflows/ci-typescript-cdk.yaml b/.github/workflows/ci-typescript-cdk.yaml index adc2dc7..6503a96 100644 --- a/.github/workflows/ci-typescript-cdk.yaml +++ b/.github/workflows/ci-typescript-cdk.yaml @@ -78,7 +78,7 @@ jobs: if: ${{ inputs.dotnet-publish-project != '' }} run: dotnet publish ${{ inputs.dotnet-publish-project }} --configuration Release --runtime linux-arm64 --self-contained - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 with: node-version: ${{ inputs.node-version }} cache: npm From e76447c8646afdc078158be33465cb5cbafaf89c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:30:48 -0400 Subject: [PATCH 3/7] Bump actions/dependency-review-action from 4 to 5 (#53) Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 4 to 5. - [Release notes](https://github.com/actions/dependency-review-action/releases) - [Commits](https://github.com/actions/dependency-review-action/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/dependency-review-action dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/callable-dependency-review.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/callable-dependency-review.yaml b/.github/workflows/callable-dependency-review.yaml index a0a3f7a..06e44ac 100644 --- a/.github/workflows/callable-dependency-review.yaml +++ b/.github/workflows/callable-dependency-review.yaml @@ -8,6 +8,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - uses: actions/dependency-review-action@v4 + - uses: actions/dependency-review-action@v5 with: fail-on-severity: high From 09135e29920cf9324f35ec2db2226593cb19352a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:30:52 -0400 Subject: [PATCH 4/7] Bump docker/setup-qemu-action from 3 to 4 (#54) Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3 to 4. - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/v3...v4) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/cd-cdk.yaml | 2 +- .github/workflows/ci-python-sam.yaml | 2 +- .github/workflows/ci-typescript-cdk.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cd-cdk.yaml b/.github/workflows/cd-cdk.yaml index 9fc541d..9ebb9d0 100644 --- a/.github/workflows/cd-cdk.yaml +++ b/.github/workflows/cd-cdk.yaml @@ -55,7 +55,7 @@ jobs: steps: - uses: actions/checkout@v6 - - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-qemu-action@v4 if: ${{ inputs.enable-qemu }} - uses: actions/setup-dotnet@v5 diff --git a/.github/workflows/ci-python-sam.yaml b/.github/workflows/ci-python-sam.yaml index b15192e..8aff356 100644 --- a/.github/workflows/ci-python-sam.yaml +++ b/.github/workflows/ci-python-sam.yaml @@ -89,7 +89,7 @@ jobs: - name: Set up QEMU if: ${{ inputs.run-cdk-synth && inputs.enable-qemu }} - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v4 - name: CDK synth if: ${{ inputs.run-cdk-synth }} diff --git a/.github/workflows/ci-typescript-cdk.yaml b/.github/workflows/ci-typescript-cdk.yaml index 6503a96..03a080d 100644 --- a/.github/workflows/ci-typescript-cdk.yaml +++ b/.github/workflows/ci-typescript-cdk.yaml @@ -66,7 +66,7 @@ jobs: steps: - uses: actions/checkout@v6 - - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-qemu-action@v4 if: ${{ inputs.enable-qemu }} - uses: actions/setup-dotnet@v5 From 06cab504be39f9df41f5ff376f40006e326c1366 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:33:45 -0400 Subject: [PATCH 5/7] Bump actions/labeler from 5 to 6 (#55) Bumps [actions/labeler](https://github.com/actions/labeler) from 5 to 6. - [Release notes](https://github.com/actions/labeler/releases) - [Commits](https://github.com/actions/labeler/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/labeler dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/callable-labeler.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/callable-labeler.yaml b/.github/workflows/callable-labeler.yaml index cc48824..c4c6a91 100644 --- a/.github/workflows/callable-labeler.yaml +++ b/.github/workflows/callable-labeler.yaml @@ -81,7 +81,7 @@ jobs: - '**/*.test.ts' - '**/*_test.py' EOF - - uses: actions/labeler@v5 + - uses: actions/labeler@v6 with: repo-token: ${{ secrets.GITHUB_TOKEN }} configuration-path: ${{ runner.temp }}/labeler.yml From dea18763ee3eabc2c0e6b73ead1fc5435c48cc27 Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Fri, 12 Jun 2026 16:05:18 -0400 Subject: [PATCH 6/7] Add ci-static reusable workflow and content label rule (#56) - ci-static.yaml: reusable CI for static HTML/CSS/JS sites (S3+CloudFront repos with no build framework). Job 'ci' emits the 'ci / ci' status context required by the org main-branch ruleset, which static sites previously could not satisfy (only ci-dotnet/python-sam/typescript-cdk existed). Checks: htmlhint, JSON-LD validity, sitemap well-formedness, internal-link/asset resolution, README/.gitignore conventions. - callable-labeler.yaml: add a 'content' rule (html/css/assets/sitemap/ robots) so static-site PRs get labeled instead of matching nothing. --- .github/workflows/callable-labeler.yaml | 8 ++ .github/workflows/ci-static.yaml | 168 ++++++++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 .github/workflows/ci-static.yaml diff --git a/.github/workflows/callable-labeler.yaml b/.github/workflows/callable-labeler.yaml index c4c6a91..8232ae4 100644 --- a/.github/workflows/callable-labeler.yaml +++ b/.github/workflows/callable-labeler.yaml @@ -56,6 +56,14 @@ jobs: - 'lambdas/**' - 'api/**' - 'services/**' + content: + - changed-files: + - any-glob-to-any-file: + - '**/*.html' + - '**/*.css' + - 'assets/**' + - 'sitemap.xml' + - 'robots.txt' ci: - changed-files: - any-glob-to-any-file: diff --git a/.github/workflows/ci-static.yaml b/.github/workflows/ci-static.yaml new file mode 100644 index 0000000..6d0f903 --- /dev/null +++ b/.github/workflows/ci-static.yaml @@ -0,0 +1,168 @@ +name: CI — Static Site + +# Reusable CI for static HTML/CSS/JS sites (S3 + CloudFront repos with no build +# framework). Emits the `ci / ci` status context required by the org "main branch +# protection" ruleset, which language-specific CI reusables already satisfy but +# static sites previously could not. +# +# All checks are dependency-light: htmlhint via npx, everything else via the +# python3 / xmllint preinstalled on ubuntu runners. No per-repo config needed. +# +# Caller example (.github/workflows/ci.yaml): +# name: CI +# on: +# pull_request: +# branches: [main] +# jobs: +# ci: +# uses: Sea-Haven-Industries/.github/.github/workflows/ci-static.yaml@main + +on: + workflow_call: + inputs: + html-glob: + description: "Glob of HTML files to lint/validate" + type: string + default: "**/*.html" + node-version: + description: "Node.js version for htmlhint" + type: string + default: "24" + run-htmlhint: + description: "Run htmlhint structural validation" + type: boolean + default: true + run-jsonld-check: + description: "Validate every application/ld+json block parses as JSON" + type: boolean + default: true + run-sitemap-check: + description: "Validate sitemap.xml is well-formed XML (if present)" + type: boolean + default: true + run-link-check: + description: "Verify root-relative internal links and asset references resolve to files in the repo" + type: boolean + default: true + run-conventions-check: + description: "Require README.md and a .gitignore that covers .env" + type: boolean + default: true + +permissions: + contents: read + +jobs: + ci: + runs-on: ubuntu-latest + timeout-minutes: 15 + concurrency: + group: ci-static-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-node@v6 + if: ${{ inputs.run-htmlhint }} + with: + node-version: ${{ inputs.node-version }} + + - name: HTMLHint + if: ${{ inputs.run-htmlhint }} + run: | + cat > "${RUNNER_TEMP}/.htmlhintrc" <<'EOF' + { + "tagname-lowercase": true, + "attr-lowercase": true, + "attr-value-double-quotes": true, + "doctype-first": true, + "doctype-html5": true, + "tag-pair": true, + "spec-char-escape": false, + "id-unique": true, + "src-not-empty": true, + "attr-no-duplication": true, + "title-require": true, + "alt-require": true + } + EOF + npx --yes htmlhint --config "${RUNNER_TEMP}/.htmlhintrc" "${{ inputs.html-glob }}" + + - name: Validate JSON-LD blocks + if: ${{ inputs.run-jsonld-check }} + run: | + python3 - <<'PY' + import glob, json, re, sys + errs = 0 + for path in sorted(glob.glob("**/*.html", recursive=True)): + html = open(path, encoding="utf-8").read() + for m in re.finditer( + r']*type="application/ld\+json"[^>]*>(.*?)', html, re.S + ): + try: + json.loads(m.group(1).strip()) + except Exception as e: + print(f"::error file={path}::Invalid JSON-LD: {e}") + errs += 1 + print("All JSON-LD blocks valid." if not errs else f"{errs} invalid JSON-LD block(s).") + sys.exit(1 if errs else 0) + PY + + - name: Validate sitemap.xml + if: ${{ inputs.run-sitemap-check }} + run: | + python3 - <<'PY' + import os, sys, xml.dom.minidom as M + errs = 0 + if os.path.exists("sitemap.xml"): + try: + M.parse("sitemap.xml") + print("sitemap.xml is well-formed.") + except Exception as e: + print(f"::error file=sitemap.xml::Malformed XML: {e}") + errs += 1 + else: + print("::warning::No sitemap.xml found.") + sys.exit(1 if errs else 0) + PY + + - name: Check internal links and asset references + if: ${{ inputs.run-link-check }} + run: | + python3 - <<'PY' + import glob, os, re, sys + errs = 0 + for path in sorted(glob.glob("**/*.html", recursive=True)): + html = open(path, encoding="utf-8").read() + for attr in ("href", "src"): + for m in re.finditer(rf'{attr}="([^"]+)"', html): + url = m.group(1) + if re.match(r'^(https?:|mailto:|tel:|#|data:|//|javascript:)', url): + continue + target = url.split("?")[0].split("#")[0] + if not target.startswith("/"): + continue # skip relative links; root-relative is the repo convention + p = target.lstrip("/") + if not any(os.path.exists(c) for c in (p, os.path.join(p, "index.html"))): + print(f"::error file={path}::Broken internal reference: {url}") + errs += 1 + print("All internal references resolve." if not errs else f"{errs} broken internal reference(s).") + sys.exit(1 if errs else 0) + PY + + - name: Conventions check + if: ${{ inputs.run-conventions-check }} + run: | + errors=0 + fail() { echo "::error::$1"; errors=$((errors + 1)); } + [[ -f README.md ]] || fail "Missing README.md" + if [[ -f .gitignore ]]; then + grep -qE '^\.env$|^\.env\b' .gitignore || fail ".gitignore does not include .env" + else + fail "Missing .gitignore" + fi + if [[ $errors -gt 0 ]]; then + echo "Conventions check failed with $errors error(s)." + exit 1 + fi + echo "Conventions check passed." From e43a9cb4477e61840664a9a3b87e1ecd7827ec18 Mon Sep 17 00:00:00 2001 From: Adam Moussa Date: Fri, 12 Jun 2026 16:29:19 -0400 Subject: [PATCH 7/7] ci-static: add build mode for templated static sites Add check-dir + build-command inputs. When build-command is set, run npm ci + the build, then validate the built output in check-dir (e.g. _site) instead of repo source. Without this, a site that templates its HTML (Eleventy etc.) has no source HTML and the checks pass vacuously. Backward-compatible: defaults (check-dir='.', build-command='') preserve source-mode behavior for existing callers. build-command is passed via env to avoid expression injection into the run script. --- .github/workflows/ci-static.yaml | 87 +++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci-static.yaml b/.github/workflows/ci-static.yaml index 6d0f903..0b764a3 100644 --- a/.github/workflows/ci-static.yaml +++ b/.github/workflows/ci-static.yaml @@ -1,31 +1,38 @@ name: CI — Static Site -# Reusable CI for static HTML/CSS/JS sites (S3 + CloudFront repos with no build -# framework). Emits the `ci / ci` status context required by the org "main branch -# protection" ruleset, which language-specific CI reusables already satisfy but -# static sites previously could not. +# Reusable CI for static HTML/CSS/JS sites (S3 + CloudFront repos). Emits the +# `ci / ci` status context required by the org "main branch protection" ruleset. # -# All checks are dependency-light: htmlhint via npx, everything else via the -# python3 / xmllint preinstalled on ubuntu runners. No per-repo config needed. +# Supports two modes: +# - Source mode (default): validates HTML in place at the repo root. +# - Build mode: set `build-command` (e.g. an Eleventy build) + `check-dir` +# (e.g. "_site") so the checks validate the BUILT output that actually +# ships — not the source templates. Without this, a templated site's +# source has no plain HTML and the checks would pass vacuously. # -# Caller example (.github/workflows/ci.yaml): -# name: CI -# on: -# pull_request: -# branches: [main] +# All checks are dependency-light: htmlhint via npx, the rest via python3. +# +# Caller example (build mode): # jobs: # ci: # uses: Sea-Haven-Industries/.github/.github/workflows/ci-static.yaml@main +# with: +# build-command: "npx @11ty/eleventy" +# check-dir: "_site" on: workflow_call: inputs: - html-glob: - description: "Glob of HTML files to lint/validate" + check-dir: + description: "Directory the checks run against (repo root in source mode, build output dir in build mode)" type: string - default: "**/*.html" + default: "." + build-command: + description: "Optional build command to run before checks (implies `npm ci` first). Leave empty for source mode." + type: string + default: "" node-version: - description: "Node.js version for htmlhint" + description: "Node.js version for build / htmlhint" type: string default: "24" run-htmlhint: @@ -41,11 +48,11 @@ on: type: boolean default: true run-link-check: - description: "Verify root-relative internal links and asset references resolve to files in the repo" + description: "Verify root-relative internal links and asset references resolve to files" type: boolean default: true run-conventions-check: - description: "Require README.md and a .gitignore that covers .env" + description: "Require README.md and a .gitignore that covers .env (always run against repo root)" type: boolean default: true @@ -59,14 +66,28 @@ jobs: concurrency: group: ci-static-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true + env: + CHECK_DIR: ${{ inputs.check-dir }} + BUILD_COMMAND: ${{ inputs.build-command }} steps: - uses: actions/checkout@v6 - uses: actions/setup-node@v6 - if: ${{ inputs.run-htmlhint }} + if: ${{ inputs.run-htmlhint || inputs.build-command != '' }} with: node-version: ${{ inputs.node-version }} + - name: Build site + if: ${{ inputs.build-command != '' }} + run: | + npm ci + # build-command passed via env to avoid expression injection into the script body + eval "$BUILD_COMMAND" + if [[ ! -d "$CHECK_DIR" ]]; then + echo "::error::build-command did not produce check-dir '$CHECK_DIR'" + exit 1 + fi + - name: HTMLHint if: ${{ inputs.run-htmlhint }} run: | @@ -86,15 +107,16 @@ jobs: "alt-require": true } EOF - npx --yes htmlhint --config "${RUNNER_TEMP}/.htmlhintrc" "${{ inputs.html-glob }}" + npx --yes htmlhint --config "${RUNNER_TEMP}/.htmlhintrc" "${CHECK_DIR%/}/**/*.html" - name: Validate JSON-LD blocks if: ${{ inputs.run-jsonld-check }} run: | python3 - <<'PY' - import glob, json, re, sys + import glob, json, os, re, sys + base = os.environ.get("CHECK_DIR", ".") errs = 0 - for path in sorted(glob.glob("**/*.html", recursive=True)): + for path in sorted(glob.glob(os.path.join(base, "**/*.html"), recursive=True)): html = open(path, encoding="utf-8").read() for m in re.finditer( r']*type="application/ld\+json"[^>]*>(.*?)', html, re.S @@ -113,16 +135,18 @@ jobs: run: | python3 - <<'PY' import os, sys, xml.dom.minidom as M + base = os.environ.get("CHECK_DIR", ".") + p = os.path.join(base, "sitemap.xml") errs = 0 - if os.path.exists("sitemap.xml"): + if os.path.exists(p): try: - M.parse("sitemap.xml") + M.parse(p) print("sitemap.xml is well-formed.") except Exception as e: - print(f"::error file=sitemap.xml::Malformed XML: {e}") + print(f"::error file={p}::Malformed XML: {e}") errs += 1 else: - print("::warning::No sitemap.xml found.") + print(f"::warning::No sitemap.xml found in {base}") sys.exit(1 if errs else 0) PY @@ -131,8 +155,9 @@ jobs: run: | python3 - <<'PY' import glob, os, re, sys + base = os.environ.get("CHECK_DIR", ".") errs = 0 - for path in sorted(glob.glob("**/*.html", recursive=True)): + for path in sorted(glob.glob(os.path.join(base, "**/*.html"), recursive=True)): html = open(path, encoding="utf-8").read() for attr in ("href", "src"): for m in re.finditer(rf'{attr}="([^"]+)"', html): @@ -141,9 +166,13 @@ jobs: continue target = url.split("?")[0].split("#")[0] if not target.startswith("/"): - continue # skip relative links; root-relative is the repo convention - p = target.lstrip("/") - if not any(os.path.exists(c) for c in (p, os.path.join(p, "index.html"))): + continue # root-relative is the repo convention + rel = target.lstrip("/") + cands = ( + os.path.join(base, rel), + os.path.join(base, rel, "index.html"), + ) + if not any(os.path.exists(c) for c in cands): print(f"::error file={path}::Broken internal reference: {url}") errs += 1 print("All internal references resolve." if not errs else f"{errs} broken internal reference(s).")