From cc60a35da5acce722dbf0d655e3133067425a03a Mon Sep 17 00:00:00 2001 From: Greg Born Date: Wed, 25 Feb 2026 00:05:29 +0000 Subject: [PATCH] Add interactive GCP project setup script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds scripts/setup-gcp-project.sh — an interactive wizard that automates Google Cloud Platform setup for AgentCloak: - Prompts for project name, ID, redirect URI, and support email with sensible defaults (press Enter to accept) - Creates GCP project, links billing, enables Gmail + People APIs - Pauses with step-by-step instructions for manual consent screen configuration (scopes, test users) with direct console links and copy-paste scope string - Validates consent screen exists after manual step - Creates OAuth 2.0 credentials via API once consent screen is ready - Generates .env with SESSION_SECRET and DATABASE_ENCRYPTION_KEY auto-generated via openssl rand, plus all OAuth values filled in - Warns before overwriting existing .env README updated with automated setup as the recommended path (manual steps collapsed into a
block), and project structure updated to include scripts/. Created by gregb and his home-grown crew of builders 🦜 🤖 --- README.md | 28 +++ scripts/setup-gcp-project.sh | 401 +++++++++++++++++++++++++++++++++++ 2 files changed, 429 insertions(+) create mode 100755 scripts/setup-gcp-project.sh diff --git a/README.md b/README.md index 0c5cfaa..80ce6e8 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,8 @@ agentcloak/ │ ├── web/ # Web dashboard (React + Tailwind + Vite) │ ├── cli/ # CLI for setup, key management, filters, password reset │ └── mcp-stdio/ # Stdio proxy for stdio-only environments +├── scripts/ # Setup and utility scripts +│ └── setup-gcp-project.sh # Automated GCP project setup └── deploy/ ├── docker/ # Docker deployment └── cloudflare/ # Cloudflare Workers (planned) @@ -103,6 +105,30 @@ Google OAuth is **optional**. You only need it if you want: If you don't need either, skip to [step 3](#3-configure-environment). +**Automated setup (recommended):** + +The `scripts/setup-gcp-project.sh` script walks you through project creation, API enablement, consent screen configuration, and credential generation. It prompts for each value with sensible defaults — press Enter to accept: + +```bash +./scripts/setup-gcp-project.sh +``` + +``` + GCP Account: you@gmail.com + +Press Enter to accept the default shown in [brackets]. + + Project name [AgentCloak]: + Project ID [agentcloak-a1b2c3d4]: + OAuth redirect URI [http://localhost:3000/auth/callback]: + Consent screen support email [you@gmail.com]: +``` + +Requires the [gcloud CLI](https://cloud.google.com/sdk/docs/install) (`gcloud auth login` first). The script generates a `.env` file with `SESSION_SECRET` and `DATABASE_ENCRYPTION_KEY` auto-generated via `openssl rand`, and fills in the Google OAuth credentials. If an existing `.env` is found, it asks before overwriting. If any GCP API call fails (Google's consent screen API can be finicky on new projects), it prints direct console links and manual instructions for the remaining steps. + +
+Manual setup (click to expand) + **Create a project and enable the Gmail API:** 1. Go to the [Google Cloud Console](https://console.cloud.google.com/) @@ -148,6 +174,8 @@ If you don't need either, skip to [step 3](#3-configure-environment). > If you changed the port in your `.env`, use that port instead. 15. Click **Create**. Copy the **Client ID** and **Client Secret** — you'll need them in the next step. +
+ ### 3. Configure environment ```bash diff --git a/scripts/setup-gcp-project.sh b/scripts/setup-gcp-project.sh new file mode 100755 index 0000000..b2a17d8 --- /dev/null +++ b/scripts/setup-gcp-project.sh @@ -0,0 +1,401 @@ +#!/usr/bin/env bash +# +# setup-gcp-project.sh — Create a Google Cloud Platform project for AgentCloak +# +# Interactive wizard that creates the GCP project, enables the Gmail API, +# configures the OAuth consent screen, creates OAuth 2.0 credentials, and +# generates a .env file with auto-generated secrets. +# Prompts for each value with sensible defaults — press Enter to accept. +# +# Prerequisites: +# - gcloud CLI installed (https://cloud.google.com/sdk/docs/install) +# - Logged in: gcloud auth login +# - A billing account linked (required for enabling APIs) +# +# Usage: +# ./scripts/setup-gcp-project.sh +# +set -euo pipefail + +# ─── Helpers ──────────────────────────────────────────────────────────────── + +# Prompt with a default value. Empty input accepts the default. +prompt() { + local label="$1" default="$2" result + read -rp " $label [$default]: " result + echo "${result:-$default}" +} + +# ─── Preflight checks ────────────────────────────────────────────────────── + +if ! command -v gcloud &>/dev/null; then + echo "Error: gcloud CLI is not installed." + echo "Install it from https://cloud.google.com/sdk/docs/install" + exit 1 +fi + +ACCOUNT=$(gcloud config get-value account 2>/dev/null || true) +if [[ -z "$ACCOUNT" ]]; then + echo "Error: Not logged in. Run: gcloud auth login" + exit 1 +fi + +# ─── Interactive prompts ──────────────────────────────────────────────────── + +DEFAULT_PROJECT_ID="agentcloak-$(head -c 4 /dev/urandom | xxd -p)" + +echo "" +echo "============================================" +echo " AgentCloak — GCP Project Setup" +echo "============================================" +echo "" +echo " GCP Account: $ACCOUNT" +echo "" +echo "Press Enter to accept the default shown in [brackets]." +echo "" + +PROJECT_NAME=$(prompt "Project name" "AgentCloak") +PROJECT_ID=$(prompt "Project ID" "$DEFAULT_PROJECT_ID") +REDIRECT_URI=$(prompt "OAuth redirect URI" "http://localhost:3000/auth/callback") +SUPPORT_EMAIL=$(prompt "Consent screen support email" "$ACCOUNT") + +echo "" +echo " ── Summary ──────────────────────────────" +echo " Project name: $PROJECT_NAME" +echo " Project ID: $PROJECT_ID" +echo " Redirect URI: $REDIRECT_URI" +echo " Support email: $SUPPORT_EMAIL" +echo " ─────────────────────────────────────────" +echo "" +read -rp " Continue? [Y/n] " confirm +if [[ "${confirm,,}" == "n" ]]; then + echo "Aborted." + exit 0 +fi + +# ─── 1. Create the project ───────────────────────────────────────────────── + +echo "" +echo ">>> Step 1/6: Creating project '$PROJECT_ID' ..." + +if gcloud projects describe "$PROJECT_ID" &>/dev/null; then + echo " Project already exists — reusing it." +else + gcloud projects create "$PROJECT_ID" --name="$PROJECT_NAME" + echo " Created." +fi + +gcloud config set project "$PROJECT_ID" + +# ─── 2. Link billing (required for enabling APIs) ────────────────────────── + +echo "" +echo ">>> Step 2/6: Checking billing ..." + +BILLING_ACCOUNT=$(gcloud billing accounts list \ + --filter="open=true" \ + --format="value(ACCOUNT_ID)" \ + --limit=1 2>/dev/null || true) + +if [[ -z "$BILLING_ACCOUNT" ]]; then + echo " Warning: No billing account found." + echo " You may need to link one manually at:" + echo " https://console.cloud.google.com/billing/linkedaccount?project=$PROJECT_ID" +else + CURRENT_BILLING=$(gcloud billing projects describe "$PROJECT_ID" \ + --format="value(billingAccountName)" 2>/dev/null || true) + + if [[ -z "$CURRENT_BILLING" || "$CURRENT_BILLING" == "billingAccounts/" ]]; then + gcloud billing projects link "$PROJECT_ID" --billing-account="$BILLING_ACCOUNT" + echo " Linked billing account: $BILLING_ACCOUNT" + else + echo " Billing already linked." + fi +fi + +# ─── 3. Enable required APIs ─────────────────────────────────────────────── + +echo "" +echo ">>> Step 3/6: Enabling APIs ..." + +gcloud services enable gmail.googleapis.com +echo " Gmail API — enabled." + +gcloud services enable people.googleapis.com +echo " People API — enabled." + +# ─── 4. Configure the OAuth consent screen ────────────────────────────────── + +echo "" +echo ">>> Step 4/6: Configuring OAuth consent screen ..." + +ACCESS_TOKEN=$(gcloud auth print-access-token) +BRAND_NAME="" +CONSENT_URL="https://console.cloud.google.com/apis/credentials/consent?project=$PROJECT_ID" + +# Check if OAuth brand already exists +EXISTING_BRANDS=$(curl -sf \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + "https://oauth2.googleapis.com/v1/projects/$PROJECT_ID/brands" 2>/dev/null || echo "{}") + +BRAND_NAME=$(echo "$EXISTING_BRANDS" | grep -o '"name":"[^"]*"' | head -1 | cut -d'"' -f4 || true) + +if [[ -n "$BRAND_NAME" ]]; then + echo " Consent screen already configured." +else + # Try to create the brand via API first + BRAND_RESPONSE=$(curl -s \ + -X POST \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{ + \"applicationTitle\": \"$PROJECT_NAME\", + \"supportEmail\": \"$SUPPORT_EMAIL\" + }" \ + "https://oauth2.googleapis.com/v1/projects/$PROJECT_ID/brands") + + BRAND_NAME=$(echo "$BRAND_RESPONSE" | grep -o '"name":"[^"]*"' | head -1 | cut -d'"' -f4 || true) + + if [[ -n "$BRAND_NAME" ]]; then + echo " Consent screen created via API (Testing mode)." + fi +fi + +# Whether the brand was created via API or already existed, the user still +# needs to configure scopes and add test users in the console. Pause here. +SCOPES_URL="https://console.cloud.google.com/auth/scopes?project=$PROJECT_ID" +STEP=1 + +echo "" +echo " ┌─────────────────────────────────────────────────────────────┐" +echo " │ Manual step required: configure the consent screen │" +echo " └─────────────────────────────────────────────────────────────┘" +echo "" +echo " If you haven't already created the OAuth consent screen app," +echo " open this URL first:" +echo "" +echo " $CONSENT_URL" +echo "" +echo " $((STEP)). Click 'Continue'"; ((STEP++)) +echo " $((STEP)). Enter App name: $PROJECT_NAME"; ((STEP++)) +echo " $((STEP)). Enter User support email: $SUPPORT_EMAIL"; ((STEP++)) +echo " $((STEP)). Select 'External' under Audience, then click 'Next'"; ((STEP++)) +echo " $((STEP)). Enter your email as the Contact email address"; ((STEP++)) +echo " $((STEP)). Check the agreement box and click 'Continue'"; ((STEP++)) +echo " $((STEP)). Click 'Create'"; ((STEP++)) +echo "" +echo " If the consent screen app already exists, skip to the next part." +echo "" +echo " ── Add OAuth Scopes ──────────────────────────────────────────" +echo "" +echo " Open the Scopes page:" +echo " $SCOPES_URL" +echo "" +echo " $((STEP)). Click 'Add or Remove Scopes'"; ((STEP++)) +echo " $((STEP)). Scroll down to 'Manually add scopes' and paste this:"; ((STEP++)) +echo "" +echo " openid,https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/userinfo.profile,https://www.googleapis.com/auth/gmail.readonly,https://www.googleapis.com/auth/gmail.compose" +echo "" +echo " $((STEP)). Click 'Add to Table', then click 'Update', then click 'Save'"; ((STEP++)) +echo "" +echo " ── Add Test Users ────────────────────────────────────────────" +echo "" +echo " $((STEP)). Add the Gmail address(es) you want to access through AgentCloak"; ((STEP++)) +echo " $((STEP)). Click 'Save and Continue' through remaining pages" +echo "" +read -rp " Press Enter when done (or 's' to skip) ... " consent_done + +if [[ "${consent_done,,}" == "s" ]]; then + echo " Skipped — you can finish consent screen setup later." +fi + +# Re-fetch brand and validate +echo "" +echo " Verifying consent screen ..." +ACCESS_TOKEN=$(gcloud auth print-access-token) +EXISTING_BRANDS=$(curl -sf \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + "https://oauth2.googleapis.com/v1/projects/$PROJECT_ID/brands" 2>/dev/null || echo "{}") +BRAND_NAME=$(echo "$EXISTING_BRANDS" | grep -o '"name":"[^"]*"' | head -1 | cut -d'"' -f4 || true) + +if [[ -n "$BRAND_NAME" ]]; then + echo " Consent screen found." + echo "" + echo " Note: Google does not expose configured scopes via API, so we" + echo " cannot verify them automatically. If you see auth errors later," + echo " check that all 5 scopes were added at:" + echo " $SCOPES_URL" +else + echo " Warning: Consent screen not found. Credential creation will be skipped." + echo " You can finish setup later at: $CONSENT_URL" +fi + +# ─── 5. Create OAuth 2.0 credentials ─────────────────────────────────────── + +echo "" +echo ">>> Step 5/6: Creating OAuth 2.0 credentials ..." + +# Extract origin from redirect URI (e.g., http://localhost:3000) +ORIGIN=$(echo "$REDIRECT_URI" | sed -E 's|(https?://[^/]+).*|\1|') + +CREDS_MANUAL=false +CLIENT_ID="" +CLIENT_SECRET="" + +if [[ -z "$BRAND_NAME" ]]; then + echo " Skipped — consent screen must be configured first." + CREDS_MANUAL=true +else + CRED_RESPONSE=$(curl -sf \ + -X POST \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{ + \"client_id\": { + \"application_type\": \"WEB\", + \"redirect_uris\": [\"$REDIRECT_URI\"], + \"js_origins\": [\"$ORIGIN\"], + \"display_name\": \"$PROJECT_NAME Web\" + } + }" \ + "https://oauth2.googleapis.com/v1/$BRAND_NAME/clients" 2>/dev/null || echo "{}") + + CLIENT_ID=$(echo "$CRED_RESPONSE" | grep -o '"clientId":"[^"]*"' | head -1 | cut -d'"' -f4 || true) + CLIENT_SECRET=$(echo "$CRED_RESPONSE" | grep -o '"clientSecret":"[^"]*"' | head -1 | cut -d'"' -f4 || true) + + if [[ -n "$CLIENT_ID" && -n "$CLIENT_SECRET" ]]; then + echo " Credentials created." + else + CREDS_MANUAL=true + fi +fi + +if [[ "$CREDS_MANUAL" == true ]]; then + CLIENT_ID="${CLIENT_ID:-}" + CLIENT_SECRET="${CLIENT_SECRET:-}" + echo "" + echo " Could not create credentials automatically." + echo " Create them manually:" + echo " 1. Open https://console.cloud.google.com/apis/credentials?project=$PROJECT_ID" + echo " 2. Click 'Create Credentials' > 'OAuth client ID'" + echo " 3. Application type: Web application" + echo " 4. Name: $PROJECT_NAME Web" + echo " 5. Authorized JavaScript origins: $ORIGIN" + echo " 6. Authorized redirect URIs: $REDIRECT_URI" + echo " 7. Update GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in the .env file" +fi + +# ─── 6. Generate .env file ────────────────────────────────────────────────── + +echo "" +echo ">>> Step 6/6: Generating .env file ..." + +# Resolve project root (one level up from scripts/) +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +ENV_FILE="$PROJECT_ROOT/.env" + +# Auto-generate secrets +SESSION_SECRET=$(openssl rand -hex 32) +DATABASE_ENCRYPTION_KEY=$(openssl rand -hex 32) + +# Derive BASE_URL from redirect URI +BASE_URL=$(echo "$REDIRECT_URI" | sed -E 's|(https?://[^/]+).*|\1|') + +# Extract port from BASE_URL (default 3000) +PORT=$(echo "$BASE_URL" | grep -oE ':[0-9]+$' | tr -d ':') +PORT="${PORT:-3000}" + +if [[ -f "$ENV_FILE" ]]; then + echo "" + echo " .env already exists at $ENV_FILE" + read -rp " Overwrite it? [y/N] " overwrite + if [[ "${overwrite,,}" != "y" ]]; then + echo " Skipped — .env not modified." + echo "" + echo " Generated values (add manually):" + echo " SESSION_SECRET=$SESSION_SECRET" + echo " DATABASE_ENCRYPTION_KEY=$DATABASE_ENCRYPTION_KEY" + echo " GOOGLE_CLIENT_ID=$CLIENT_ID" + echo " GOOGLE_CLIENT_SECRET=$CLIENT_SECRET" + echo " GOOGLE_REDIRECT_URI=$REDIRECT_URI" + echo "" + + echo "============================================" + echo " GCP setup complete!" + echo "============================================" + exit 0 + fi +fi + +cat > "$ENV_FILE" <