blumeops/mise-tasks/mirror-create

80 lines
2.3 KiB
Text
Raw Permalink Normal View History

#!/usr/bin/env bash
#MISE description="Create a new upstream mirror in the mirrors/ Forgejo org"
#USAGE arg "<url>" help="Upstream git URL to mirror (e.g. https://github.com/org/repo.git)"
#USAGE flag "--name <name>" help="Repository name on forge (default: derived from URL)"
#USAGE flag "--description <description>" help="Repository description"
#USAGE flag "--dry-run" help="Show what would be done without creating"
set -euo pipefail
Expose Forgejo publicly at forge.eblu.me (#278) ## Summary Expose Forgejo publicly at `forge.eblu.me` via the Fly.io reverse proxy — the first dynamic, authenticated public-facing service. - **Forgejo hardening:** Domain changed to forge.eblu.me, SSH stays on forge.ops.eblu.me, reverse proxy trust headers configured, local registration locked to external-only (Authentik SSO) - **Tailscale Ingress:** ExternalName Service + Ingress in tailscale-operator creates forge.tail8d86e.ts.net endpoint - **Fly.io proxy:** nginx server block with rate-limited auth endpoints (3r/s), fail2ban with custom nginx-deny action, security headers, /swagger blocked, WebSocket support, 512m body limit - **Authentik:** OAuth callback updated to forge.eblu.me - **DNS/TLS:** CNAME record in Pulumi, cert in fly-setup - **Rename:** ~29 files updated from forge.ops.eblu.me to forge.eblu.me (HTTPS refs only; SSH, container builds, and Caddy table kept as-is) ## Deployment Order 1. `mise run provision-indri -- --tags forgejo` (config changes) 2. Verify forge.ops.eblu.me still works 3. `argocd app set tailscale-operator --revision feature/forge-public && argocd app sync tailscale-operator` 4. Verify `curl https://forge.tail8d86e.ts.net` 5. `cd fly && fly deploy` 6. Verify pre-DNS: `curl -H "Host: forge.eblu.me" https://blumeops-proxy.fly.dev/` 7. `fly certs add forge.eblu.me -a blumeops-proxy` 8. `argocd app set authentik --revision feature/forge-public && argocd app sync authentik` 9. `mise run dns-preview && mise run dns-up` 10. Full verification (see below) 11. Rehearse `mise run fly-shutoff` 12. After merge: reset ArgoCD revisions to main, re-sync ## Verification Checklist - [ ] forge.eblu.me loads, shows public repos - [ ] forge.ops.eblu.me still works from tailnet - [ ] SSH clone via forge.ops.eblu.me:2222 works - [ ] HTTPS clone via forge.eblu.me works - [ ] UI shows forge.eblu.me for HTTPS clone, forge.ops.eblu.me for SSH - [ ] /swagger returns 403 - [ ] Rapid login attempts trigger 429 rate limit - [ ] fail2ban bans after 5 failed logins in 10 minutes - [ ] ArgoCD can still sync (SSH unaffected) - [ ] `mise run fly-shutoff` stops all public traffic - [ ] `mise run services-check` passes Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/278
2026-03-03 08:40:41 -08:00
FORGE_API="https://forge.eblu.me/api/v1"
ORG="mirrors"
OP_TOKEN_REF="op://blumeops/w3663ffnvkewbftncqxtcpeavy/api-token"
OP_GITHUB_PAT_REF="op://blumeops/w3663ffnvkewbftncqxtcpeavy/github-mirror-pat"
url="${usage_url:?}"
# Derive repo name from URL if not provided
if [[ -n "${usage_name:-}" ]]; then
repo_name="${usage_name}"
else
# Strip trailing .git and extract last path component
repo_name="$(basename "$url" .git)"
fi
description="${usage_description:-}"
# Detect service type from URL
service="git"
case "$url" in
*github.com*) service="github" ;;
*codeberg.org*) service="gitea" ;;
*forgejo.org*) service="gitea" ;;
esac
echo "Mirror: $url"
echo "Forge repo: $ORG/$repo_name"
echo "Service: $service"
[[ -n "$description" ]] && echo "Description: $description"
echo
if [[ "${usage_dry_run:-}" == "true" ]]; then
echo "[dry-run] Would create mirror at ${FORGE_API}/repos/migrate"
exit 0
fi
echo "Reading secrets from 1Password..."
token="$(op read "$OP_TOKEN_REF")"
# For GitHub upstreams, include the PAT for authenticated sync
auth_token=""
if [[ "$service" == "github" ]]; then
auth_token="$(op read "$OP_GITHUB_PAT_REF")"
echo "Using GitHub PAT for authenticated mirror sync"
fi
payload=$(cat <<ENDJSON
{
"clone_addr": "$url",
"repo_name": "$repo_name",
"repo_owner": "$ORG",
"mirror": true,
"service": "$service",
"description": "$description",
"auth_token": "$auth_token"
}
ENDJSON
)
http_code=$(curl -s -o /tmp/mirror-create-response.json -w "%{http_code}" \
-X POST "${FORGE_API}/repos/migrate" \
-H "Authorization: token ${token}" \
-H "Content-Type: application/json" \
-d "$payload")
if [[ "$http_code" == "201" ]]; then
Expose Forgejo publicly at forge.eblu.me (#278) ## Summary Expose Forgejo publicly at `forge.eblu.me` via the Fly.io reverse proxy — the first dynamic, authenticated public-facing service. - **Forgejo hardening:** Domain changed to forge.eblu.me, SSH stays on forge.ops.eblu.me, reverse proxy trust headers configured, local registration locked to external-only (Authentik SSO) - **Tailscale Ingress:** ExternalName Service + Ingress in tailscale-operator creates forge.tail8d86e.ts.net endpoint - **Fly.io proxy:** nginx server block with rate-limited auth endpoints (3r/s), fail2ban with custom nginx-deny action, security headers, /swagger blocked, WebSocket support, 512m body limit - **Authentik:** OAuth callback updated to forge.eblu.me - **DNS/TLS:** CNAME record in Pulumi, cert in fly-setup - **Rename:** ~29 files updated from forge.ops.eblu.me to forge.eblu.me (HTTPS refs only; SSH, container builds, and Caddy table kept as-is) ## Deployment Order 1. `mise run provision-indri -- --tags forgejo` (config changes) 2. Verify forge.ops.eblu.me still works 3. `argocd app set tailscale-operator --revision feature/forge-public && argocd app sync tailscale-operator` 4. Verify `curl https://forge.tail8d86e.ts.net` 5. `cd fly && fly deploy` 6. Verify pre-DNS: `curl -H "Host: forge.eblu.me" https://blumeops-proxy.fly.dev/` 7. `fly certs add forge.eblu.me -a blumeops-proxy` 8. `argocd app set authentik --revision feature/forge-public && argocd app sync authentik` 9. `mise run dns-preview && mise run dns-up` 10. Full verification (see below) 11. Rehearse `mise run fly-shutoff` 12. After merge: reset ArgoCD revisions to main, re-sync ## Verification Checklist - [ ] forge.eblu.me loads, shows public repos - [ ] forge.ops.eblu.me still works from tailnet - [ ] SSH clone via forge.ops.eblu.me:2222 works - [ ] HTTPS clone via forge.eblu.me works - [ ] UI shows forge.eblu.me for HTTPS clone, forge.ops.eblu.me for SSH - [ ] /swagger returns 403 - [ ] Rapid login attempts trigger 429 rate limit - [ ] fail2ban bans after 5 failed logins in 10 minutes - [ ] ArgoCD can still sync (SSH unaffected) - [ ] `mise run fly-shutoff` stops all public traffic - [ ] `mise run services-check` passes Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/278
2026-03-03 08:40:41 -08:00
echo "Created mirror: https://forge.eblu.me/${ORG}/${repo_name}"
else
echo "Error (HTTP $http_code):"
cat /tmp/mirror-create-response.json
exit 1
fi