-
Notifications
You must be signed in to change notification settings - Fork 1
162 lines (137 loc) · 5.92 KB
/
Copy pathdeploy-cloudflare-bridge.yml
File metadata and controls
162 lines (137 loc) · 5.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
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 '%s\n' \
'https://secure-tools-web-bridge.pages.dev/*' \
' X-Robots-Tag: noindex, nofollow' \
'' \
'https://:version.secure-tools-web-bridge.pages.dev/*' \
' X-Robots-Tag: noindex, nofollow' \
> "$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 20 ]]
- 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" noindex
- name: Validate stable deployment aliases
shell: bash
run: |
smoke_with_retry() {
local url="$1"
local indexing="$2"
for attempt in 1 2 3 4 5 6; do
if node tests/deployment-smoke.mjs "$url" "$indexing"; then
return 0
fi
[[ "$attempt" -lt 6 ]] || return 1
echo "Waiting for Cloudflare alias propagation (attempt $attempt of 6)."
sleep 10
done
}
smoke_with_retry https://secure-tools-web-bridge.pages.dev noindex
smoke_with_retry https://tools.securetools.app indexable