diff --git a/.gitea/workflows/canary-staging.yml b/.gitea/workflows/canary-staging.yml index ff40d4db..d3d6b68e 100644 --- a/.gitea/workflows/canary-staging.yml +++ b/.gitea/workflows/canary-staging.yml @@ -85,7 +85,7 @@ jobs: # OpenAI fallback — kept wired so an operator-dispatched run with # E2E_RUNTIME=hermes overridden via workflow_dispatch can still # exercise the OpenAI path without re-editing the workflow. - E2E_OPENAI_API_KEY: ${{ secrets.MOLECULE_STAGING_OPENAI_KEY }} + E2E_OPENAI_API_KEY: ${{ secrets.MOLECULE_STAGING_OPENAI_API_KEY }} E2E_MODE: canary E2E_RUNTIME: claude-code # Pin the canary to a specific MiniMax model rather than relying @@ -140,7 +140,7 @@ jobs: fi ;; langgraph|hermes) - required_secret_name="MOLECULE_STAGING_OPENAI_KEY" + required_secret_name="MOLECULE_STAGING_OPENAI_API_KEY" required_secret_value="${E2E_OPENAI_API_KEY:-}" ;; *) diff --git a/.gitea/workflows/continuous-synth-e2e.yml b/.gitea/workflows/continuous-synth-e2e.yml index f0ed9e8f..299d42e0 100644 --- a/.gitea/workflows/continuous-synth-e2e.yml +++ b/.gitea/workflows/continuous-synth-e2e.yml @@ -147,7 +147,7 @@ jobs: # E2E_RUNTIME=langgraph or =hermes and still have a working # canary path. The script picks the right blob shape based on # which key is non-empty. - E2E_OPENAI_API_KEY: ${{ secrets.MOLECULE_STAGING_OPENAI_KEY }} + E2E_OPENAI_API_KEY: ${{ secrets.MOLECULE_STAGING_OPENAI_API_KEY }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -175,7 +175,7 @@ jobs: # LLM-key requirement is per-runtime: claude-code accepts # EITHER MiniMax OR direct-Anthropic (whichever is set first), - # langgraph + hermes use OpenAI (MOLECULE_STAGING_OPENAI_KEY). + # langgraph + hermes use OpenAI (MOLECULE_STAGING_OPENAI_API_KEY). case "${E2E_RUNTIME}" in claude-code) if [ -n "${E2E_MINIMAX_API_KEY:-}" ]; then @@ -190,7 +190,7 @@ jobs: fi ;; langgraph|hermes) - required_secret_name="MOLECULE_STAGING_OPENAI_KEY" + required_secret_name="MOLECULE_STAGING_OPENAI_API_KEY" required_secret_value="${E2E_OPENAI_API_KEY:-}" ;; *) diff --git a/.gitea/workflows/e2e-staging-saas.yml b/.gitea/workflows/e2e-staging-saas.yml index f0e501f6..7b6c093b 100644 --- a/.gitea/workflows/e2e-staging-saas.yml +++ b/.gitea/workflows/e2e-staging-saas.yml @@ -105,7 +105,7 @@ jobs: # OpenAI fallback — kept wired so an operator-dispatched run with # E2E_RUNTIME=hermes or =langgraph via workflow_dispatch can still # exercise the OpenAI path. - E2E_OPENAI_API_KEY: ${{ secrets.MOLECULE_STAGING_OPENAI_KEY }} + E2E_OPENAI_API_KEY: ${{ secrets.MOLECULE_STAGING_OPENAI_API_KEY }} E2E_RUNTIME: ${{ github.event.inputs.runtime || 'claude-code' }} # Pin the model when running on the default claude-code path — # the per-runtime default ("sonnet") routes to direct Anthropic @@ -152,7 +152,7 @@ jobs: fi ;; langgraph|hermes) - required_secret_name="MOLECULE_STAGING_OPENAI_KEY" + required_secret_name="MOLECULE_STAGING_OPENAI_API_KEY" required_secret_value="${E2E_OPENAI_API_KEY:-}" ;; *) diff --git a/.gitea/workflows/sweep-aws-secrets.yml b/.gitea/workflows/sweep-aws-secrets.yml index afa8f6fa..a6572e8e 100644 --- a/.gitea/workflows/sweep-aws-secrets.yml +++ b/.gitea/workflows/sweep-aws-secrets.yml @@ -73,8 +73,8 @@ jobs: AWS_REGION: ${{ secrets.AWS_REGION || 'us-east-1' }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_JANITOR_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_JANITOR_SECRET_ACCESS_KEY }} - CP_PROD_ADMIN_TOKEN: ${{ secrets.CP_PROD_ADMIN_TOKEN }} - CP_STAGING_ADMIN_TOKEN: ${{ secrets.CP_STAGING_ADMIN_TOKEN }} + CP_ADMIN_API_TOKEN: ${{ secrets.CP_ADMIN_API_TOKEN }} + CP_STAGING_ADMIN_API_TOKEN: ${{ secrets.CP_STAGING_ADMIN_API_TOKEN }} MAX_DELETE_PCT: ${{ github.event.inputs.max_delete_pct || '50' }} GRACE_HOURS: ${{ github.event.inputs.grace_hours || '24' }} @@ -90,7 +90,7 @@ jobs: # they already accepted the repo state) run: | missing=() - for var in AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY CP_PROD_ADMIN_TOKEN CP_STAGING_ADMIN_TOKEN; do + for var in AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY CP_ADMIN_API_TOKEN CP_STAGING_ADMIN_API_TOKEN; do if [ -z "${!var:-}" ]; then missing+=("$var") fi diff --git a/.gitea/workflows/sweep-cf-orphans.yml b/.gitea/workflows/sweep-cf-orphans.yml index 18dc41cb..b18630b7 100644 --- a/.gitea/workflows/sweep-cf-orphans.yml +++ b/.gitea/workflows/sweep-cf-orphans.yml @@ -75,8 +75,8 @@ jobs: env: CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }} CF_ZONE_ID: ${{ secrets.CF_ZONE_ID }} - CP_PROD_ADMIN_TOKEN: ${{ secrets.CP_PROD_ADMIN_TOKEN }} - CP_STAGING_ADMIN_TOKEN: ${{ secrets.CP_STAGING_ADMIN_TOKEN }} + CP_ADMIN_API_TOKEN: ${{ secrets.CP_ADMIN_API_TOKEN }} + CP_STAGING_ADMIN_API_TOKEN: ${{ secrets.CP_STAGING_ADMIN_API_TOKEN }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: us-east-2 @@ -109,7 +109,7 @@ jobs: # so they can rerun after fixing the secret) run: | missing=() - for var in CF_API_TOKEN CF_ZONE_ID CP_PROD_ADMIN_TOKEN CP_STAGING_ADMIN_TOKEN AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY; do + for var in CF_API_TOKEN CF_ZONE_ID CP_ADMIN_API_TOKEN CP_STAGING_ADMIN_API_TOKEN AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY; do if [ -z "${!var:-}" ]; then missing+=("$var") fi diff --git a/.gitea/workflows/sweep-cf-tunnels.yml b/.gitea/workflows/sweep-cf-tunnels.yml index 3fdc06c1..1fa12cfd 100644 --- a/.gitea/workflows/sweep-cf-tunnels.yml +++ b/.gitea/workflows/sweep-cf-tunnels.yml @@ -70,8 +70,8 @@ jobs: env: CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }} CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }} - CP_PROD_ADMIN_TOKEN: ${{ secrets.CP_PROD_ADMIN_TOKEN }} - CP_STAGING_ADMIN_TOKEN: ${{ secrets.CP_STAGING_ADMIN_TOKEN }} + CP_ADMIN_API_TOKEN: ${{ secrets.CP_ADMIN_API_TOKEN }} + CP_STAGING_ADMIN_API_TOKEN: ${{ secrets.CP_STAGING_ADMIN_API_TOKEN }} MAX_DELETE_PCT: ${{ github.event.inputs.max_delete_pct || '90' }} steps: @@ -89,7 +89,7 @@ jobs: # they already accepted the repo state) run: | missing=() - for var in CF_API_TOKEN CF_ACCOUNT_ID CP_PROD_ADMIN_TOKEN CP_STAGING_ADMIN_TOKEN; do + for var in CF_API_TOKEN CF_ACCOUNT_ID CP_ADMIN_API_TOKEN CP_STAGING_ADMIN_API_TOKEN; do if [ -z "${!var:-}" ]; then missing+=("$var") fi diff --git a/scripts/ops/sweep-aws-secrets.sh b/scripts/ops/sweep-aws-secrets.sh index 55db0a11..20450026 100755 --- a/scripts/ops/sweep-aws-secrets.sh +++ b/scripts/ops/sweep-aws-secrets.sh @@ -40,8 +40,8 @@ # # Env vars required: # AWS_REGION — region the secrets live in (default: us-east-1) -# CP_PROD_ADMIN_TOKEN — CP admin bearer for api.moleculesai.app -# CP_STAGING_ADMIN_TOKEN — CP admin bearer for staging-api.moleculesai.app +# CP_ADMIN_API_TOKEN — CP admin bearer for api.moleculesai.app +# CP_STAGING_ADMIN_API_TOKEN — CP admin bearer for staging-api.moleculesai.app # AWS_ACCESS_KEY_ID, — IAM principal with secretsmanager:ListSecrets # AWS_SECRET_ACCESS_KEY and secretsmanager:DeleteSecret. Note: the # prod molecule-cp principal does NOT have @@ -88,8 +88,8 @@ need() { exit 1 fi } -need CP_PROD_ADMIN_TOKEN -need CP_STAGING_ADMIN_TOKEN +need CP_ADMIN_API_TOKEN +need CP_STAGING_ADMIN_API_TOKEN need AWS_ACCESS_KEY_ID need AWS_SECRET_ACCESS_KEY @@ -107,13 +107,13 @@ log() { echo "[$(date -u +%H:%M:%S)] $*"; } # response includes both `id` and `slug`; we extract `id` here. log "Fetching CP prod org ids..." -PROD_IDS=$(curl -sS -m 15 -H "Authorization: Bearer $CP_PROD_ADMIN_TOKEN" \ +PROD_IDS=$(curl -sS -m 15 -H "Authorization: Bearer $CP_ADMIN_API_TOKEN" \ "https://api.moleculesai.app/cp/admin/orgs?limit=500" \ | python3 -c "import json,sys; print(' '.join(o['id'] for o in json.load(sys.stdin).get('orgs',[])))") log " prod orgs: $(echo "$PROD_IDS" | wc -w | tr -d ' ')" log "Fetching CP staging org ids..." -STAGING_IDS=$(curl -sS -m 15 -H "Authorization: Bearer $CP_STAGING_ADMIN_TOKEN" \ +STAGING_IDS=$(curl -sS -m 15 -H "Authorization: Bearer $CP_STAGING_ADMIN_API_TOKEN" \ "https://staging-api.moleculesai.app/cp/admin/orgs?limit=500" \ | python3 -c "import json,sys; print(' '.join(o['id'] for o in json.load(sys.stdin).get('orgs',[])))") log " staging orgs: $(echo "$STAGING_IDS" | wc -w | tr -d ' ')" diff --git a/scripts/ops/sweep-cf-orphans.sh b/scripts/ops/sweep-cf-orphans.sh index 569bcbcf..8a4da90c 100755 --- a/scripts/ops/sweep-cf-orphans.sh +++ b/scripts/ops/sweep-cf-orphans.sh @@ -20,8 +20,8 @@ # Env vars required: # CF_API_TOKEN — Cloudflare token with zone:dns:edit # CF_ZONE_ID — the zone (moleculesai.app) -# CP_PROD_ADMIN_TOKEN — CP admin bearer for api.moleculesai.app -# CP_STAGING_ADMIN_TOKEN — CP admin bearer for staging-api.moleculesai.app +# CP_ADMIN_API_TOKEN — CP admin bearer for api.moleculesai.app +# CP_STAGING_ADMIN_API_TOKEN — CP admin bearer for staging-api.moleculesai.app # AWS_* — standard AWS creds (default region us-east-2) # # Exit codes: @@ -58,21 +58,21 @@ need() { } need CF_API_TOKEN need CF_ZONE_ID -need CP_PROD_ADMIN_TOKEN -need CP_STAGING_ADMIN_TOKEN +need CP_ADMIN_API_TOKEN +need CP_STAGING_ADMIN_API_TOKEN log() { echo "[$(date -u +%H:%M:%S)] $*"; } # --- Gather live sets ------------------------------------------------------ log "Fetching CP prod org slugs..." -PROD_SLUGS=$(curl -sS -m 15 -H "Authorization: Bearer $CP_PROD_ADMIN_TOKEN" \ +PROD_SLUGS=$(curl -sS -m 15 -H "Authorization: Bearer $CP_ADMIN_API_TOKEN" \ "https://api.moleculesai.app/cp/admin/orgs?limit=500" \ | python3 -c "import json,sys; print(' '.join(o['slug'] for o in json.load(sys.stdin).get('orgs',[])))") log " prod orgs: $(echo "$PROD_SLUGS" | wc -w | tr -d ' ')" log "Fetching CP staging org slugs..." -STAGING_SLUGS=$(curl -sS -m 15 -H "Authorization: Bearer $CP_STAGING_ADMIN_TOKEN" \ +STAGING_SLUGS=$(curl -sS -m 15 -H "Authorization: Bearer $CP_STAGING_ADMIN_API_TOKEN" \ "https://staging-api.moleculesai.app/cp/admin/orgs?limit=500" \ | python3 -c "import json,sys; print(' '.join(o['slug'] for o in json.load(sys.stdin).get('orgs',[])))") log " staging orgs: $(echo "$STAGING_SLUGS" | wc -w | tr -d ' ')" diff --git a/scripts/ops/sweep-cf-tunnels.sh b/scripts/ops/sweep-cf-tunnels.sh index bf948940..13734db3 100755 --- a/scripts/ops/sweep-cf-tunnels.sh +++ b/scripts/ops/sweep-cf-tunnels.sh @@ -31,8 +31,8 @@ # token must include the tunnel scope.) # CF_ACCOUNT_ID — the account that owns the tunnels (visible # in dash.cloudflare.com URL path) -# CP_PROD_ADMIN_TOKEN — CP admin bearer for api.moleculesai.app -# CP_STAGING_ADMIN_TOKEN — CP admin bearer for staging-api.moleculesai.app +# CP_ADMIN_API_TOKEN — CP admin bearer for api.moleculesai.app +# CP_STAGING_ADMIN_API_TOKEN — CP admin bearer for staging-api.moleculesai.app # # Exit codes: # 0 — dry-run completed or sweep executed successfully @@ -72,21 +72,21 @@ need() { } need CF_API_TOKEN need CF_ACCOUNT_ID -need CP_PROD_ADMIN_TOKEN -need CP_STAGING_ADMIN_TOKEN +need CP_ADMIN_API_TOKEN +need CP_STAGING_ADMIN_API_TOKEN log() { echo "[$(date -u +%H:%M:%S)] $*"; } # --- Gather live sets ------------------------------------------------------ log "Fetching CP prod org slugs..." -PROD_SLUGS=$(curl -sS -m 15 -H "Authorization: Bearer $CP_PROD_ADMIN_TOKEN" \ +PROD_SLUGS=$(curl -sS -m 15 -H "Authorization: Bearer $CP_ADMIN_API_TOKEN" \ "https://api.moleculesai.app/cp/admin/orgs?limit=500" \ | python3 -c "import json,sys; print(' '.join(o['slug'] for o in json.load(sys.stdin).get('orgs',[])))") log " prod orgs: $(echo "$PROD_SLUGS" | wc -w | tr -d ' ')" log "Fetching CP staging org slugs..." -STAGING_SLUGS=$(curl -sS -m 15 -H "Authorization: Bearer $CP_STAGING_ADMIN_TOKEN" \ +STAGING_SLUGS=$(curl -sS -m 15 -H "Authorization: Bearer $CP_STAGING_ADMIN_API_TOKEN" \ "https://staging-api.moleculesai.app/cp/admin/orgs?limit=500" \ | python3 -c "import json,sys; print(' '.join(o['slug'] for o in json.load(sys.stdin).get('orgs',[])))") log " staging orgs: $(echo "$STAGING_SLUGS" | wc -w | tr -d ' ')" diff --git a/tests/e2e/test_staging_full_saas.sh b/tests/e2e/test_staging_full_saas.sh index 2caece5c..b494f8f3 100755 --- a/tests/e2e/test_staging_full_saas.sh +++ b/tests/e2e/test_staging_full_saas.sh @@ -341,7 +341,7 @@ tenant_call() { # MiniMax account). Lower friction than MiniMax for operators # who already have an Anthropic API key for their own Claude # Code session. Pricier per-token than MiniMax but billing is -# still independent of MOLECULE_STAGING_OPENAI_KEY. Pinned to the +# still independent of MOLECULE_STAGING_OPENAI_API_KEY. Pinned to the # claude-code runtime — hermes/langgraph use OpenAI-shaped envs. # # E2E_OPENAI_API_KEY → langgraph + hermes paths. Kept as fallback @@ -368,7 +368,7 @@ elif [ -n "${E2E_ANTHROPIC_API_KEY:-}" ]; then # who already have an Anthropic API key (e.g. for their own Claude # Code session) and want to avoid setting up a separate MiniMax # account just for E2E. Pricier per-token than MiniMax but billing - # is still independent of MOLECULE_STAGING_OPENAI_KEY, so an OpenAI + # is still independent of MOLECULE_STAGING_OPENAI_API_KEY, so an OpenAI # quota collapse doesn't wedge this path. Pinned to the claude-code # runtime: hermes/langgraph use OpenAI-shaped envs and won't honour # ANTHROPIC_API_KEY without further wiring (out of scope for this @@ -623,7 +623,7 @@ fi # "Encrypted content is not supported" → hermes codex_responses API misroute (#14) # "Unknown provider" → bridge misconfigured PROVIDER= (regression of #13 fix) # "hermes-agent unreachable" → gateway process died -# "exceeded your current quota" → MOLECULE_STAGING_OPENAI_KEY billing (NOT a platform regression — #2578) +# "exceeded your current quota" → MOLECULE_STAGING_OPENAI_API_KEY billing (NOT a platform regression — #2578) # # Fail LOUD with the specific pattern so CI log + alert channel makes the # regression unambiguous. @@ -657,7 +657,7 @@ fi # with a provider-side 429, that is a billing event on the configured # OpenAI key, not a platform regression. Tracked in #2578. if echo "$AGENT_TEXT" | grep -qiE "exceeded your current quota|insufficient_quota"; then - fail "A2A — PROVIDER QUOTA EXHAUSTED (NOT a platform regression). Operator action: top up MOLECULE_STAGING_OPENAI_KEY billing or rotate to a higher-quota org at Settings → Secrets and Variables → Actions. Tracked in #2578. Raw: $AGENT_TEXT" + fail "A2A — PROVIDER QUOTA EXHAUSTED (NOT a platform regression). Operator action: top up MOLECULE_STAGING_OPENAI_API_KEY billing or rotate to a higher-quota org at Settings → Secrets and Variables → Actions. Tracked in #2578. Raw: $AGENT_TEXT" fi # Generic catch-all — falls through if none of the known regressions hit. if echo "$AGENT_TEXT" | grep -qiE "error|exception"; then