Skip to content

Merge pull request #71 from SecureToolsProject/infra/h3-tools-subdomain #3

Merge pull request #71 from SecureToolsProject/infra/h3-tools-subdomain

Merge pull request #71 from SecureToolsProject/infra/h3-tools-subdomain #3

name: Deploy Cloudflare bridge
on:
push:
branches:
- main
workflow_dispatch:
permissions:
contents: read
deployments: write
concurrency:
group: web-utilities-cloudflare-bridge
cancel-in-progress: false
jobs:
deploy:
name: Deploy Web Utilities bridge
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Check out repository
# actions/checkout v6.0.2
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 24
- name: Run static tool validation
run: node tests/run-all.mjs
- name: Validate bridge prerequisites
shell: bash
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: |
set -euo pipefail
missing=()
[[ -n "$CLOUDFLARE_API_TOKEN" ]] || missing+=(CLOUDFLARE_API_TOKEN)
[[ -n "$CLOUDFLARE_ACCOUNT_ID" ]] || missing+=(CLOUDFLARE_ACCOUNT_ID)
if (( ${#missing[@]} > 0 )); then
printf '::error::Missing required GitHub Actions secret: %s\n' "${missing[@]}"
exit 1
fi
[[ "$(<CNAME)" == "securetools.app" ]] || {
echo "::error file=CNAME::Existing GitHub Pages custom domain changed"
exit 1
}
- name: Prepare isolated bridge artifact
shell: bash
env:
BRIDGE_DIRECTORY: ${{ runner.temp }}/secure-tools-web-bridge
run: |
set -euo pipefail
mkdir -p "$BRIDGE_DIRECTORY"
cp -R \
404.html \
index.html \
about \
assets \
css \
js \
privacy \
robots.txt \
sitemap.xml \
tools \
"$BRIDGE_DIRECTORY/"
printf '/*\n X-Robots-Tag: noindex, nofollow\n' > "$BRIDGE_DIRECTORY/_headers"
[[ ! -e "$BRIDGE_DIRECTORY/CNAME" ]]
[[ ! -e "$BRIDGE_DIRECTORY/_redirects" ]]
[[ ! -e "$BRIDGE_DIRECTORY/_worker.js" ]]
[[ ! -d "$BRIDGE_DIRECTORY/functions" ]]
[[ "$(find "$BRIDGE_DIRECTORY" -name index.html -type f | wc -l)" -eq 19 ]]
- name: Validate Cloudflare Pages project isolation
shell: bash
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: |
set -euo pipefail
project="$(curl --fail --silent --show-error \
"https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/pages/projects/secure-tools-web-bridge" \
--header "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}")"
jq --raw-output '
.result as $project |
"Pages project state: name=\($project.name), production_branch=\($project.production_branch), subdomain=\($project.subdomain), custom_domains=\($project.domains // [] | map(select(. != $project.subdomain)) | sort | join(",")), source=\(if $project.source == null then "direct-upload" else $project.source.type end), web_analytics=\(if ($project.build_config.web_analytics_tag // "") == "" and ($project.build_config.web_analytics_token // "") == "" then "disabled" else "enabled" end)"
' <<< "$project"
jq --exit-status '
.result as $project |
.success == true and
$project.name == "secure-tools-web-bridge" and
$project.production_branch == "main" and
$project.subdomain == "secure-tools-web-bridge.pages.dev" and
($project.domains // [] | map(select(. != $project.subdomain)) | sort) == ["tools.securetools.app"] and
$project.source == null and
($project.build_config.web_analytics_tag // "") == "" and
($project.build_config.web_analytics_token // "") == ""
' <<< "$project" > /dev/null || {
echo "::error::Cloudflare Pages project is missing or violates the H3.3 parallel-domain contract"
exit 1
}
echo "Validated Direct Upload project secure-tools-web-bridge: production branch main, stable pages.dev subdomain plus tools.securetools.app, no Git integration, no Web Analytics."
- name: Deploy to Cloudflare Pages
id: deploy
# cloudflare/wrangler-action v4.0.0
uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
command: pages deploy "${{ runner.temp }}/secure-tools-web-bridge" --project-name=secure-tools-web-bridge --branch=main --commit-hash=${{ github.sha }}
- name: Validate deployed bridge
env:
DEPLOYMENT_URL: ${{ steps.deploy.outputs.deployment-url }}
run: node tests/deployment-smoke.mjs "$DEPLOYMENT_URL"
- name: Validate stable bridge alias
run: node tests/deployment-smoke.mjs https://secure-tools-web-bridge.pages.dev
- name: Validate tools custom domain
run: node tests/deployment-smoke.mjs https://tools.securetools.app
- name: Validate existing GitHub Pages production
run: node tests/deployment-smoke.mjs https://securetools.app production