gowalk-cicd 1.0.49 → 1.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +4 -0
- package/README.md +2 -0
- package/action/.daemux-version +1 -1
- package/android-action/.daemux-version +1 -1
- package/backend-action/.daemux-version +1 -1
- package/backend-action/action.yml +7 -4
- package/backend-action/remote_deploy.sh +26 -7
- package/backend-action/select_certbot_account.sh +18 -0
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -108,6 +108,10 @@ node /path/to/gowalk-cicd/bin/cli.mjs
|
|
|
108
108
|
- The mobile workflow's feature-branch-only `backend-preview` job bootstraps a
|
|
109
109
|
new app before GitHub registers `deploy-backend.yml` on the default branch.
|
|
110
110
|
Default-branch deploys continue through the separate backend workflow.
|
|
111
|
+
- Domain-backed backend deploys fail closed on certificate issuance and the
|
|
112
|
+
public HTTPS health probe. `select_certbot_account.sh` chooses one existing
|
|
113
|
+
Let's Encrypt ACME v2 account deterministically so multi-account hosts stay
|
|
114
|
+
non-interactive; legacy v1 account directories are not valid candidates.
|
|
111
115
|
- The Android action serves two build systems. `android_config.project_kind()`
|
|
112
116
|
is the only place that decides which; every downstream step branches on the
|
|
113
117
|
`project_kind` output rather than re-sniffing the repo. Flutter wins the tie
|
package/README.md
CHANGED
|
@@ -73,6 +73,8 @@ The backend workflow runs on a GitHub-hosted runner and, on a push touching
|
|
|
73
73
|
it rsyncs the backend dir to `/opt/gowalk-backends/<app>/`, runs
|
|
74
74
|
`docker compose up -d --build`, auto-detects the published `127.0.0.1:<port>`,
|
|
75
75
|
wires an nginx vhost + Let's Encrypt cert for the API domain, and health-checks.
|
|
76
|
+
Hosts with several existing Let's Encrypt accounts select one deterministically,
|
|
77
|
+
and a domain deploy fails unless its public HTTPS certificate and health route validate.
|
|
76
78
|
|
|
77
79
|
Requirements on the consumer repo:
|
|
78
80
|
|
package/action/.daemux-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.51
|
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.51
|
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.51
|
|
@@ -122,9 +122,12 @@ runs:
|
|
|
122
122
|
rsync -az -e "$SSH" "$COMPOSE_FILE" \
|
|
123
123
|
"${{ inputs.ssh-user }}@${{ inputs.host }}:$DEST/docker-compose.yml"
|
|
124
124
|
fi
|
|
125
|
-
#
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
# Ship remote helpers after the application mirror. Both are package
|
|
126
|
+
# owned and kept out of the consumer's source tree.
|
|
127
|
+
rsync -az -e "$SSH" \
|
|
128
|
+
"${{ github.action_path }}/remote_deploy.sh" \
|
|
129
|
+
"${{ github.action_path }}/select_certbot_account.sh" \
|
|
130
|
+
"${{ inputs.ssh-user }}@${{ inputs.host }}:$DEST/"
|
|
128
131
|
|
|
129
132
|
- name: Deploy on the host
|
|
130
133
|
shell: bash
|
|
@@ -140,7 +143,7 @@ runs:
|
|
|
140
143
|
"umask 077; cat > '$DEST/.runtime.env'"
|
|
141
144
|
fi
|
|
142
145
|
$SSH "${{ inputs.ssh-user }}@${{ inputs.host }}" \
|
|
143
|
-
"bash '$DEST
|
|
146
|
+
"bash '$DEST/remote_deploy.sh' \
|
|
144
147
|
'${{ inputs.app-name }}' '${{ inputs.api-domain }}' \
|
|
145
148
|
'${{ inputs.health-path }}' '${{ inputs.cert-email }}'"
|
|
146
149
|
|
|
@@ -10,6 +10,7 @@ HEALTH="${3:-/health}"
|
|
|
10
10
|
CERT_EMAIL="${4:-admin@gowalk.com}"
|
|
11
11
|
DIR="/opt/gowalk-backends/$APP"
|
|
12
12
|
cd "$DIR"
|
|
13
|
+
source "$DIR/select_certbot_account.sh"
|
|
13
14
|
|
|
14
15
|
log() { echo "[deploy $APP] $*"; }
|
|
15
16
|
|
|
@@ -95,16 +96,34 @@ fi
|
|
|
95
96
|
# ── Let's Encrypt cert (idempotent; certbot skips if current)
|
|
96
97
|
if ! certbot certificates 2>/dev/null | grep -q "Domains: $DOMAIN\b"; then
|
|
97
98
|
log "requesting LE cert for $DOMAIN"
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
CERTBOT_ACCOUNT="$(select_certbot_account)"
|
|
100
|
+
CERTBOT_ARGS=()
|
|
101
|
+
if [ -n "$CERTBOT_ACCOUNT" ]; then
|
|
102
|
+
log "using an existing Let's Encrypt account"
|
|
103
|
+
CERTBOT_ARGS+=(--account "$CERTBOT_ACCOUNT")
|
|
104
|
+
fi
|
|
105
|
+
if ! certbot --nginx -d "$DOMAIN" --non-interactive --agree-tos \
|
|
106
|
+
--email "$CERT_EMAIL" --redirect "${CERTBOT_ARGS[@]}"; then
|
|
107
|
+
log "ERROR: certbot failed for $DOMAIN"
|
|
108
|
+
exit 1
|
|
109
|
+
fi
|
|
100
110
|
else
|
|
101
111
|
log "cert for $DOMAIN already present"
|
|
102
112
|
fi
|
|
103
113
|
|
|
104
|
-
# ── public health-check
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
114
|
+
# ── public health-check. This validates DNS, the certificate, nginx routing,
|
|
115
|
+
# and the application together; a green deploy must mean the public API works.
|
|
116
|
+
PUBLIC_HEALTHY=""
|
|
117
|
+
for i in $(seq 1 15); do
|
|
118
|
+
if curl -fsS "https://$DOMAIN$HEALTH" >/dev/null 2>&1; then
|
|
119
|
+
log "public https://$DOMAIN$HEALTH healthy (after ${i}x2s)"
|
|
120
|
+
PUBLIC_HEALTHY=1
|
|
121
|
+
break
|
|
122
|
+
fi
|
|
123
|
+
sleep 2
|
|
124
|
+
done
|
|
125
|
+
if [ -z "$PUBLIC_HEALTHY" ]; then
|
|
126
|
+
log "ERROR: public https://$DOMAIN$HEALTH failed TLS or health validation"
|
|
127
|
+
exit 1
|
|
109
128
|
fi
|
|
110
129
|
log "done"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Print the stable id of one existing Certbot account. Hosts may contain more
|
|
4
|
+
# than one registered account; non-interactive Certbot otherwise stops to ask
|
|
5
|
+
# which account should authorize a new certificate.
|
|
6
|
+
select_certbot_account() {
|
|
7
|
+
local accounts_dir="${1:-/etc/letsencrypt/accounts}"
|
|
8
|
+
local server_dir="$accounts_dir/acme-v02.api.letsencrypt.org/directory"
|
|
9
|
+
local registration
|
|
10
|
+
|
|
11
|
+
registration="$(
|
|
12
|
+
find "$server_dir" -type f -name regr.json -print 2>/dev/null \
|
|
13
|
+
| LC_ALL=C sort \
|
|
14
|
+
| head -1
|
|
15
|
+
)"
|
|
16
|
+
[ -n "$registration" ] || return 0
|
|
17
|
+
basename "$(dirname "$registration")"
|
|
18
|
+
}
|