mirror of
https://github.com/Sea-Haven-Industries/.github.git
synced 2026-10-03 22:33:14 +00:00
Merge branch 'main' into ci-actionlint-gate
This commit is contained in:
commit
5937ab73e6
8 changed files with 216 additions and 11 deletions
|
|
@ -8,6 +8,6 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/dependency-review-action@v4
|
- uses: actions/dependency-review-action@v5
|
||||||
with:
|
with:
|
||||||
fail-on-severity: high
|
fail-on-severity: high
|
||||||
|
|
|
||||||
10
.github/workflows/callable-labeler.yaml
vendored
10
.github/workflows/callable-labeler.yaml
vendored
|
|
@ -56,6 +56,14 @@ jobs:
|
||||||
- 'lambdas/**'
|
- 'lambdas/**'
|
||||||
- 'api/**'
|
- 'api/**'
|
||||||
- 'services/**'
|
- 'services/**'
|
||||||
|
content:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- '**/*.html'
|
||||||
|
- '**/*.css'
|
||||||
|
- 'assets/**'
|
||||||
|
- 'sitemap.xml'
|
||||||
|
- 'robots.txt'
|
||||||
ci:
|
ci:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
|
|
@ -81,7 +89,7 @@ jobs:
|
||||||
- '**/*.test.ts'
|
- '**/*.test.ts'
|
||||||
- '**/*_test.py'
|
- '**/*_test.py'
|
||||||
EOF
|
EOF
|
||||||
- uses: actions/labeler@v5
|
- uses: actions/labeler@v6
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
configuration-path: ${{ runner.temp }}/labeler.yml
|
configuration-path: ${{ runner.temp }}/labeler.yml
|
||||||
|
|
|
||||||
4
.github/workflows/cd-cdk.yaml
vendored
4
.github/workflows/cd-cdk.yaml
vendored
|
|
@ -55,7 +55,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- uses: docker/setup-qemu-action@v3
|
- uses: docker/setup-qemu-action@v4
|
||||||
if: ${{ inputs.enable-qemu }}
|
if: ${{ inputs.enable-qemu }}
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v5
|
- uses: actions/setup-dotnet@v5
|
||||||
|
|
@ -67,7 +67,7 @@ jobs:
|
||||||
if: ${{ inputs.dotnet-publish-project != '' }}
|
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
|
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:
|
with:
|
||||||
node-version: ${{ inputs.node-version }}
|
node-version: ${{ inputs.node-version }}
|
||||||
|
|
||||||
|
|
|
||||||
4
.github/workflows/cd-mobile-ios.yaml
vendored
4
.github/workflows/cd-mobile-ios.yaml
vendored
|
|
@ -67,13 +67,13 @@ jobs:
|
||||||
role-to-assume: ${{ secrets.deploy-role-arn }}
|
role-to-assume: ${{ secrets.deploy-role-arn }}
|
||||||
aws-region: ${{ inputs.region }}
|
aws-region: ${{ inputs.region }}
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: ${{ inputs.node-version }}
|
node-version: ${{ inputs.node-version }}
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: ${{ inputs.cache-dependency-path }}
|
cache-dependency-path: ${{ inputs.cache-dependency-path }}
|
||||||
|
|
||||||
- uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1
|
- uses: ruby/setup-ruby@12fd324f1d0b43274fdc8130f6980590a667c455 # v1
|
||||||
with:
|
with:
|
||||||
ruby-version: ${{ inputs.ruby-version }}
|
ruby-version: ${{ inputs.ruby-version }}
|
||||||
bundler-cache: true
|
bundler-cache: true
|
||||||
|
|
|
||||||
4
.github/workflows/ci-python-sam.yaml
vendored
4
.github/workflows/ci-python-sam.yaml
vendored
|
|
@ -83,13 +83,13 @@ jobs:
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
if: ${{ inputs.run-cdk-synth }}
|
if: ${{ inputs.run-cdk-synth }}
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: ${{ inputs.node-version }}
|
node-version: ${{ inputs.node-version }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
if: ${{ inputs.run-cdk-synth && inputs.enable-qemu }}
|
if: ${{ inputs.run-cdk-synth && inputs.enable-qemu }}
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
- name: CDK synth
|
- name: CDK synth
|
||||||
if: ${{ inputs.run-cdk-synth }}
|
if: ${{ inputs.run-cdk-synth }}
|
||||||
|
|
|
||||||
197
.github/workflows/ci-static.yaml
vendored
Normal file
197
.github/workflows/ci-static.yaml
vendored
Normal file
|
|
@ -0,0 +1,197 @@
|
||||||
|
name: CI — Static Site
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# 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:
|
||||||
|
check-dir:
|
||||||
|
description: "Directory the checks run against (repo root in source mode, build output dir in build mode)"
|
||||||
|
type: string
|
||||||
|
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 build / 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"
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
run-conventions-check:
|
||||||
|
description: "Require README.md and a .gitignore that covers .env (always run against repo root)"
|
||||||
|
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
|
||||||
|
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 || 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: |
|
||||||
|
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" "${CHECK_DIR%/}/**/*.html"
|
||||||
|
|
||||||
|
- name: Validate JSON-LD blocks
|
||||||
|
if: ${{ inputs.run-jsonld-check }}
|
||||||
|
run: |
|
||||||
|
python3 - <<'PY'
|
||||||
|
import glob, json, os, re, sys
|
||||||
|
base = os.environ.get("CHECK_DIR", ".")
|
||||||
|
errs = 0
|
||||||
|
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'<script[^>]*type="application/ld\+json"[^>]*>(.*?)</script>', 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
|
||||||
|
base = os.environ.get("CHECK_DIR", ".")
|
||||||
|
p = os.path.join(base, "sitemap.xml")
|
||||||
|
errs = 0
|
||||||
|
if os.path.exists(p):
|
||||||
|
try:
|
||||||
|
M.parse(p)
|
||||||
|
print("sitemap.xml is well-formed.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"::error file={p}::Malformed XML: {e}")
|
||||||
|
errs += 1
|
||||||
|
else:
|
||||||
|
print(f"::warning::No sitemap.xml found in {base}")
|
||||||
|
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
|
||||||
|
base = os.environ.get("CHECK_DIR", ".")
|
||||||
|
errs = 0
|
||||||
|
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):
|
||||||
|
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 # 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).")
|
||||||
|
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."
|
||||||
4
.github/workflows/ci-typescript-cdk.yaml
vendored
4
.github/workflows/ci-typescript-cdk.yaml
vendored
|
|
@ -66,7 +66,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- uses: docker/setup-qemu-action@v3
|
- uses: docker/setup-qemu-action@v4
|
||||||
if: ${{ inputs.enable-qemu }}
|
if: ${{ inputs.enable-qemu }}
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v5
|
- uses: actions/setup-dotnet@v5
|
||||||
|
|
@ -78,7 +78,7 @@ jobs:
|
||||||
if: ${{ inputs.dotnet-publish-project != '' }}
|
if: ${{ inputs.dotnet-publish-project != '' }}
|
||||||
run: dotnet publish ${{ inputs.dotnet-publish-project }} --configuration Release --runtime linux-arm64 --self-contained
|
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:
|
with:
|
||||||
node-version: ${{ inputs.node-version }}
|
node-version: ${{ inputs.node-version }}
|
||||||
cache: npm
|
cache: npm
|
||||||
|
|
|
||||||
2
.github/workflows/compliance-audit.yaml
vendored
2
.github/workflows/compliance-audit.yaml
vendored
|
|
@ -76,7 +76,7 @@ jobs:
|
||||||
|
|
||||||
- name: Run compliance audit
|
- name: Run compliance audit
|
||||||
id: audit
|
id: audit
|
||||||
uses: anthropics/claude-code-action@41ea7642c1436fa0ee57aae58347904b71a5af27 # v1
|
uses: anthropics/claude-code-action@0f97b95b6536c26e5f6bd90faec370d41695beca # v1
|
||||||
with:
|
with:
|
||||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||||
prompt: |
|
prompt: |
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue