Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions .github/workflows/agent-cli-provisioning.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Agent CLI Provisioning Check

on:
workflow_dispatch:
workflow_call:

jobs:
verify-agent-clis:
name: Verify provisioned agent CLIs
runs-on: [self-hosted, codex, Linux]
timeout-minutes: 10
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
persist-credentials: false

- name: Verify selected CLI binary and headless contract
shell: bash
env:
AGENT_PROVIDER: ${{ vars.AGENT_PROVIDER || 'codex' }}
FINDINGS_PROVIDER: ${{ vars.FINDINGS_PROVIDER }}
FIXER_PROVIDER: ${{ vars.FIXER_PROVIDER }}
PLANNER_PROVIDER: ${{ vars.PLANNER_PROVIDER }}
REVIEWER_PROVIDER: ${{ vars.REVIEWER_PROVIDER }}
TESTER_PROVIDER: ${{ vars.TESTER_PROVIDER }}
AGENT_EXECUTABLE: ${{ vars.AGENT_EXECUTABLE }}
FINDINGS_EXECUTABLE: ${{ vars.FINDINGS_EXECUTABLE }}
FIXER_EXECUTABLE: ${{ vars.FIXER_EXECUTABLE }}
PLANNER_EXECUTABLE: ${{ vars.PLANNER_EXECUTABLE }}
REVIEWER_EXECUTABLE: ${{ vars.REVIEWER_EXECUTABLE }}
TESTER_EXECUTABLE: ${{ vars.TESTER_EXECUTABLE }}
run: |
set -euo pipefail

providers=("$AGENT_PROVIDER" "$FINDINGS_PROVIDER" "$FIXER_PROVIDER" "$PLANNER_PROVIDER" "$REVIEWER_PROVIDER" "$TESTER_PROVIDER")
executables=("$AGENT_EXECUTABLE" "$FINDINGS_EXECUTABLE" "$FIXER_EXECUTABLE" "$PLANNER_EXECUTABLE" "$REVIEWER_EXECUTABLE" "$TESTER_EXECUTABLE")
checked=""
for index in "${!providers[@]}"; do
provider="${providers[$index]}"
[[ -z "${provider// }" ]] && continue
case "$provider" in
opencode) expected_executable=opencode ;;
codex) expected_executable=codex ;;
cursor) expected_executable=agent ;;
*) echo "Unsupported agent provider: $provider" >&2; exit 1 ;;
esac
executable="${executables[$index]:-$expected_executable}"
[[ "${executable##*/}" == "$expected_executable" ]] || { echo "Invalid $provider executable basename." >&2; exit 1; }
if ! command -v "$executable" >/dev/null 2>&1; then
[[ "$executable" == "$expected_executable" ]] || { echo "Configured executable is missing: $executable" >&2; exit 1; }
install_home="$RUNNER_TEMP/copilot-agent-$provider-$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
mkdir -p "$install_home"
case "$provider" in
codex)
curl -fsSL https://chatgpt.com/codex/install.sh | env HOME="$install_home" CODEX_HOME="$install_home/.codex" CODEX_INSTALL_DIR="$install_home/bin" CODEX_NON_INTERACTIVE=1 sh
export PATH="$install_home/bin:$PATH"
;;
opencode)
curl -fsSL https://opencode.ai/install | env HOME="$install_home" bash -s -- --no-modify-path
export PATH="$install_home/.opencode/bin:$PATH"
;;
cursor)
curl -fsSL https://cursor.com/install | env HOME="$install_home" bash
export PATH="$install_home/.local/bin:$PATH"
;;
esac
fi
actual_version="$("$executable" --version | head -n 1)"
[[ -n "${actual_version// }" ]] || { echo "$provider returned empty version output" >&2; exit 1; }
case "$provider" in
codex) "$executable" exec --help >/dev/null ;;
opencode) "$executable" run --help >/dev/null ;;
cursor) "$executable" --help >/dev/null ;;
esac
[[ " $checked " == *" $provider "* ]] || checked="$checked $provider"
done

echo "Agent CLI contract passed for: $checked."
170 changes: 170 additions & 0 deletions .github/workflows/copilot_credential_health.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
name: Copilot - Credential Health

on:
workflow_dispatch:
inputs:
check_pat:
description: Check the workflow PAT against GitHub
required: false
default: false
type: boolean
check_openai:
description: Check OPENAI_API_KEY
required: false
default: false
type: boolean
check_anthropic:
description: Check ANTHROPIC_API_KEY
required: false
default: false
type: boolean
check_google:
description: Check GOOGLE_API_KEY
required: false
default: false
type: boolean
check_openrouter:
description: Check OPENROUTER_API_KEY
required: false
default: false
type: boolean
check_cursor:
description: Check CURSOR_API_KEY
required: false
default: false
type: boolean
check_opencode:
description: Check OPENCODE_API_KEY
required: false
default: false
type: boolean
check_codex_api_key:
description: Check CODEX_API_KEY
required: false
default: false
type: boolean

permissions:
contents: read

jobs:
verify-pat:
if: ${{ inputs.check_pat }}
name: Verify PAT
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Validate PAT without exposing its value
shell: bash
env:
PAT: ${{ secrets.PAT }}
run: |
set -euo pipefail
[[ -n "${PAT:-}" ]] || { echo 'Required credential is missing.' >&2; exit 1; }
curl --fail --silent --show-error --location --max-time 20 -H "Authorization: Bearer $PAT" -H 'Accept: application/vnd.github+json' https://api.github.com/user >/dev/null
curl --fail --silent --show-error --location --max-time 20 -H "Authorization: Bearer $PAT" -H 'Accept: application/vnd.github+json' "https://api.github.com/repos/${GITHUB_REPOSITORY}" >/dev/null

verify-openai:
if: ${{ inputs.check_openai }}
name: Verify OPENAI_API_KEY
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Validate OpenAI key without exposing its value
shell: bash
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
set -euo pipefail
[[ -n "${OPENAI_API_KEY:-}" ]] || { echo 'Required credential is missing.' >&2; exit 1; }
curl --fail --silent --show-error --location --max-time 20 -H "Authorization: Bearer $OPENAI_API_KEY" https://api.openai.com/v1/models >/dev/null

verify-anthropic:
if: ${{ inputs.check_anthropic }}
name: Verify ANTHROPIC_API_KEY
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Validate Anthropic key without exposing its value
shell: bash
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
set -euo pipefail
[[ -n "${ANTHROPIC_API_KEY:-}" ]] || { echo 'Required credential is missing.' >&2; exit 1; }
curl --fail --silent --show-error --location --max-time 20 -H "x-api-key: $ANTHROPIC_API_KEY" -H 'anthropic-version: 2023-06-01' https://api.anthropic.com/v1/models >/dev/null

verify-google:
if: ${{ inputs.check_google }}
name: Verify GOOGLE_API_KEY
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Validate Google key without exposing its value
shell: bash
env:
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
run: |
set -euo pipefail
[[ -n "${GOOGLE_API_KEY:-}" ]] || { echo 'Required credential is missing.' >&2; exit 1; }
curl --fail --silent --show-error --location --max-time 20 "https://generativelanguage.googleapis.com/v1beta/models?key=$GOOGLE_API_KEY" >/dev/null

verify-openrouter:
if: ${{ inputs.check_openrouter }}
name: Verify OPENROUTER_API_KEY
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Validate OpenRouter key without exposing its value
shell: bash
env:
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
run: |
set -euo pipefail
[[ -n "${OPENROUTER_API_KEY:-}" ]] || { echo 'Required credential is missing.' >&2; exit 1; }
curl --fail --silent --show-error --location --max-time 20 -H "Authorization: Bearer $OPENROUTER_API_KEY" https://openrouter.ai/api/v1/models >/dev/null

verify-cursor:
if: ${{ inputs.check_cursor }}
name: Verify CURSOR_API_KEY
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Validate Cursor key without exposing its value
shell: bash
env:
CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }}
run: |
set -euo pipefail
[[ -n "${CURSOR_API_KEY:-}" ]] || { echo 'Required credential is missing.' >&2; exit 1; }
curl --fail --silent --show-error --location --max-time 20 -u "$CURSOR_API_KEY:" 'https://api.cursor.com/analytics/ai-code/changes?startDate=30d&page=1&pageSize=1' >/dev/null

verify-opencode:
if: ${{ inputs.check_opencode }}
name: Verify OPENCODE_API_KEY
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Validate OpenCode key without exposing its value
shell: bash
env:
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
run: |
set -euo pipefail
[[ -n "${OPENCODE_API_KEY:-}" ]] || { echo 'Required credential is missing.' >&2; exit 1; }
curl --fail --silent --show-error --location --max-time 20 -H "Authorization: Bearer $OPENCODE_API_KEY" https://opencode.ai/zen/v1/models >/dev/null

verify-codex-api-key:
if: ${{ inputs.check_codex_api_key }}
name: Verify CODEX_API_KEY
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Validate Codex API key without exposing its value
shell: bash
env:
CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }}
run: |
set -euo pipefail
[[ -n "${CODEX_API_KEY:-}" ]] || { echo 'Required credential is missing.' >&2; exit 1; }
curl --fail --silent --show-error --location --max-time 20 -H "Authorization: Bearer $CODEX_API_KEY" https://api.openai.com/v1/models >/dev/null
Loading
Loading