From 7ef7c662f3879ed068fed3cf8db561feaab8ac48 Mon Sep 17 00:00:00 2001 From: Joshua Date: Tue, 17 Feb 2026 20:50:59 -0800 Subject: [PATCH] Harden split-repo publish script with credential-helper auth --- README.md | 2 +- docs/repo-split-publish-runbook.md | 17 +++++-- scripts/publish_split_repos.sh | 74 ++++++++++++++++++++++++------ 3 files changed, 74 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 34ebcab..0eb77e6 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ README.md ## Scripts -1. `scripts/publish_split_repos.sh` - creates/pushes `launcher`, `governance`, `contracts` repos using a Gitea PAT. +1. `scripts/publish_split_repos.sh` - creates/pushes `launcher`, `governance`, `contracts` repos using either a provided Gitea PAT or git credential-helper auth for `git.workvsg.com`. ## Internationalization diff --git a/docs/repo-split-publish-runbook.md b/docs/repo-split-publish-runbook.md index 3d35e5c..ae7591f 100644 --- a/docs/repo-split-publish-runbook.md +++ b/docs/repo-split-publish-runbook.md @@ -1,12 +1,12 @@ # Repo Split Publish Runbook -Use this runbook after valid Gitea API credentials (username + PAT) are available. +Use this runbook after valid Gitea credentials are available (PAT or git credential-helper username/password). ## Local Seed Repos (already initialized) -1. `launcher` at `/Users/vsg/Documents/VSG Codex/launcher` (commit `b716b52`) -2. `governance` at `/Users/vsg/Documents/VSG Codex/governance` (commit `12d5e7c`) -3. `contracts` at `/Users/vsg/Documents/VSG Codex/contracts` (commit `082b29b`) +1. `launcher` at `/Users/vsg/Documents/VSG Codex/launcher` (commit `caf06d2`) +2. `governance` at `/Users/vsg/Documents/VSG Codex/governance` (commit `823f201`) +3. `contracts` at `/Users/vsg/Documents/VSG Codex/contracts` (commit `dbac2f0`) ## Create Remote Repos @@ -24,13 +24,20 @@ curl -fsSL -H "Authorization: token " -H "Content-Type: application/json" Repeat for `governance` and `contracts`. -Or run the helper: +Or run the helper with PAT: ```bash cd "/Users/vsg/Documents/VSG Codex/web" ./scripts/publish_split_repos.sh ``` +Or run it without arguments to use git credential helper auth for `git.workvsg.com`: + +```bash +cd "/Users/vsg/Documents/VSG Codex/web" +./scripts/publish_split_repos.sh +``` + ## Push Local Seed Repos ```bash diff --git a/scripts/publish_split_repos.sh b/scripts/publish_split_repos.sh index 3d9f2b3..1b2a07e 100755 --- a/scripts/publish_split_repos.sh +++ b/scripts/publish_split_repos.sh @@ -1,15 +1,57 @@ #!/usr/bin/env bash set -euo pipefail -if [[ $# -lt 1 ]]; then - echo "Usage: $0 [org] [host]" >&2 - exit 1 -fi +usage() { + echo "Usage: $0 [gitea_pat] [org] [host]" >&2 + echo "If gitea_pat is omitted, script tries git credential helper for host auth." >&2 +} -TOKEN="$1" +TOKEN="${1:-}" ORG="${2:-edut}" HOST="${3:-git.workvsg.com}" ROOT="/Users/vsg/Documents/VSG Codex" +AUTH_MODE="" +AUTH_USERNAME="" +AUTH_PASSWORD="" + +init_auth() { + if [[ -n "$TOKEN" ]]; then + AUTH_MODE="token" + return + fi + + local cred user pass + cred=$(printf 'protocol=https\nhost=%s\n\n' "$HOST" | git credential fill || true) + user=$(printf '%s\n' "$cred" | awk -F= '/^username=/{print $2}') + pass=$(printf '%s\n' "$cred" | awk -F= '/^password=/{print $2}') + if [[ -n "$user" && -n "$pass" ]]; then + AUTH_MODE="basic" + AUTH_USERNAME="$user" + AUTH_PASSWORD="$pass" + return + fi + + usage + echo "No PAT provided and no git credentials found for ${HOST}." >&2 + exit 1 +} + +curl_api() { + local method="$1" + local url="$2" + local data="${3:-}" + local -a cmd=(curl -sS -w "%{http_code}" -o /tmp/edut_api.out -X "$method") + if [[ "$AUTH_MODE" == "token" ]]; then + cmd+=(-H "Authorization: token ${TOKEN}") + else + cmd+=(-u "${AUTH_USERNAME}:${AUTH_PASSWORD}") + fi + if [[ -n "$data" ]]; then + cmd+=(-H 'Content-Type: application/json' -d "$data") + fi + cmd+=("$url") + "${cmd[@]}" +} create_repo() { local name="$1" @@ -18,20 +60,24 @@ create_repo() { local api="https://${HOST}/api/v1/repos/${ORG}/${name}" local status - status=$(curl -sS -o /tmp/repo_check_${name}.json -w "%{http_code}" \ - -H "Authorization: token ${TOKEN}" \ - "$api") + status=$(curl_api "GET" "$api") if [[ "$status" == "200" ]]; then echo "Repo ${ORG}/${name} already exists" return fi + if [[ "$status" != "404" ]]; then + echo "Repo check failed for ${ORG}/${name} (status=${status})" >&2 + cat /tmp/edut_api.out >&2 || true + exit 1 + fi - curl -fsSL \ - -H "Authorization: token ${TOKEN}" \ - -H 'Content-Type: application/json' \ - -X POST "https://${HOST}/api/v1/orgs/${ORG}/repos" \ - -d "{\"name\":\"${name}\",\"private\":${private},\"description\":\"${desc}\"}" >/tmp/repo_create_${name}.json + status=$(curl_api "POST" "https://${HOST}/api/v1/orgs/${ORG}/repos" "{\"name\":\"${name}\",\"private\":${private},\"description\":\"${desc}\"}") + if [[ "$status" != "201" && "$status" != "200" ]]; then + echo "Repo create failed for ${ORG}/${name} (status=${status})" >&2 + cat /tmp/edut_api.out >&2 || true + exit 1 + fi echo "Created repo ${ORG}/${name}" } @@ -51,6 +97,8 @@ wire_and_push() { echo "Pushed ${local_dir} -> ${remote_url}" } +init_auth + create_repo "launcher" "true" "EDUT free launcher shell and wallet onboarding app" create_repo "governance" "true" "EDUT deterministic governance runtime" create_repo "contracts" "false" "EDUT membership and entitlement contracts"