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
4 changes: 4 additions & 0 deletions .env-example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
TELEGRAM_BOT_TOKEN="your_telegram_bot_token_here"
GEMINI_API_KEY="your_gemini_api_key_here"
GCP_PROJECT_ID="secure-agent-demo"
ENVIRONMENT="dev"
36 changes: 36 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Lint with Ruff
run: |
ruff check .

- name: Type check with mypy
run: |
mypy agent/

- name: Test with pytest
run: |
pytest tests/ -v
70 changes: 70 additions & 0 deletions .github/workflows/deploy-to-prod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: Deploy to Production

on:
workflow_dispatch:
workflow_call:

jobs:
deploy:
runs-on: ubuntu-latest
# This job targets the 'production' environment, which is automatically
# created by the Terraform setup in `deployment/terraform/github.tf`.
# To enable manual approval for deployments, you must add a protection
# rule to this environment in your GitHub repository settings.
#
# 1. Go to your repository's Settings > Environments.
# 2. Select the 'production' environment.
# 3. Under 'Protection rules', check the 'Required reviewers' box.
# 4. Add the specific users or teams who must approve the deployment.
#
# Once configured, the workflow will pause at this step and wait for an
# authorized user to approve it before proceeding.
environment:
name: production
concurrency: production
permissions:
contents: 'read'
id-token: 'write'

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: '3.12'

- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@v2'
with:
workload_identity_provider: 'projects/${{ vars.GCP_PROJECT_NUMBER }}/locations/global/workloadIdentityPools/${{ secrets.WIF_POOL_ID }}/providers/${{ secrets.WIF_PROVIDER_ID }}'
service_account: '${{ secrets.GCP_SERVICE_ACCOUNT }}'
create_credentials_file: true
project_id: ${{ vars.CICD_PROJECT_ID }}

- name: Set up Cloud SDK
uses: 'google-github-actions/setup-gcloud@v2'

- name: Deploy to Production (Cloud Run)
run: |
gcloud run deploy adkbot \
--image ${{ vars.REGION }}-docker.pkg.dev/${{ vars.CICD_PROJECT_ID }}/${{ vars.ARTIFACT_REGISTRY_REPO_NAME }}/${{ vars.CONTAINER_NAME }} \
--region ${{ vars.REGION }} \
--project ${{ vars.PROD_PROJECT_ID }}

57 changes: 57 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Deploy to Cloud Run

on:
push:
branches:
- main

env:
PROJECT_ID: secure-agent-demo
SERVICE_NAME: adkbot
REGION: us-central1
# These will be set up in Phase 6/7
# WIF_PROVIDER: projects/123/locations/global/workloadIdentityPools/github/providers/my-repo
# WIF_SERVICE_ACCOUNT: my-service-account@my-project.iam.gserviceaccount.com

jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: 'read'
id-token: 'write' # Required for WIF

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Google Auth
id: auth
uses: 'google-github-actions/auth@v2'
with:
# Enable this once WIF is configured in GCP:
# workload_identity_provider: '${{ env.WIF_PROVIDER }}'
# service_account: '${{ env.WIF_SERVICE_ACCOUNT }}'
credentials_json: '${{ secrets.GCP_CREDENTIALS }}' # Temporary fallback

- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@v2

- name: Authorize Docker push
run: gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev

- name: Build and Push Container
run: |
IMAGE="${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/cloud-run-source-deploy/${{ env.SERVICE_NAME }}:${{ github.sha }}"
docker build -t "$IMAGE" .
docker push "$IMAGE"

- name: Deploy to Cloud Run
uses: google-github-actions/deploy-cloudrun@v2
with:
service: ${{ env.SERVICE_NAME }}
region: ${{ env.REGION }}
image: ${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/cloud-run-source-deploy/${{ env.SERVICE_NAME }}:${{ github.sha }}
flags: |
--allow-unauthenticated
--min-instances=0
--max-instances=1
62 changes: 62 additions & 0 deletions .github/workflows/pr_checks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: PR Checks

on:
pull_request:
branches:
- main
paths:
- 'agent/**'
- 'data_ingestion/**'
- 'tests/**'
- 'deployment/**'
- 'uv.lock'

jobs:
test:
runs-on: ubuntu-latest
permissions:
contents: 'read'
id-token: 'write'
steps:
- name: Checkout code
uses: actions/checkout@v4

- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@v2'
with:
workload_identity_provider: 'projects/${{ vars.GCP_PROJECT_NUMBER }}/locations/global/workloadIdentityPools/${{ secrets.WIF_POOL_ID }}/providers/${{ secrets.WIF_PROVIDER_ID }}'
service_account: '${{ secrets.GCP_SERVICE_ACCOUNT }}'
create_credentials_file: true
project_id: ${{ vars.CICD_PROJECT_ID }}


- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: '3.12'

- name: Install uv and dependencies
run: |
pip install uv==0.8.13
uv sync --locked

- name: Run unit tests
run: uv run pytest tests/unit

- name: Run integration tests
run: uv run pytest tests/integration
115 changes: 115 additions & 0 deletions .github/workflows/staging.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

name: Deploy to Staging

on:
push:
branches:
- main
paths:
- 'agent/**'
- 'data_ingestion/**'
- 'tests/**'
- 'deployment/**'
- 'uv.lock'

jobs:
deploy_and_test_staging:
runs-on: ubuntu-latest
permissions:
contents: 'read'
id-token: 'write'

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v4
with:
python-version: '3.12'

- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@v2'
with:
workload_identity_provider: 'projects/${{ vars.GCP_PROJECT_NUMBER }}/locations/global/workloadIdentityPools/${{ secrets.WIF_POOL_ID }}/providers/${{ secrets.WIF_PROVIDER_ID }}'
service_account: '${{ secrets.GCP_SERVICE_ACCOUNT }}'
create_credentials_file: true
project_id: ${{ vars.CICD_PROJECT_ID }}

- name: Set up Cloud SDK
uses: 'google-github-actions/setup-gcloud@v2'

- name: Configure Docker for Artifact Registry
run: |
gcloud auth configure-docker ${{ vars.REGION }}-docker.pkg.dev --quiet

- name: Build and Push Docker Image
run: |
docker build -t ${{ vars.REGION }}-docker.pkg.dev/${{ vars.CICD_PROJECT_ID }}/${{ vars.ARTIFACT_REGISTRY_REPO_NAME }}/${{ vars.CONTAINER_NAME }} \
--build-arg COMMIT_SHA=${{ github.sha }} \
.
docker push ${{ vars.REGION }}-docker.pkg.dev/${{ vars.CICD_PROJECT_ID }}/${{ vars.ARTIFACT_REGISTRY_REPO_NAME }}/${{ vars.CONTAINER_NAME }}

- name: Deploy to Staging (Cloud Run)
run: |
gcloud run deploy adkbot \
--image ${{ vars.REGION }}-docker.pkg.dev/${{ vars.CICD_PROJECT_ID }}/${{ vars.ARTIFACT_REGISTRY_REPO_NAME }}/${{ vars.CONTAINER_NAME }} \
--region ${{ vars.REGION }} \
--project ${{ vars.STAGING_PROJECT_ID }}

- name: Fetch Staging Service URL
id: fetch-url
run: |
_STAGING_URL=$(gcloud run services describe adkbot \
--region ${{ vars.REGION }} --project ${{ vars.STAGING_PROJECT_ID }} --format="value(status.url)")
echo "_staging_url=${_STAGING_URL}" >> $GITHUB_OUTPUT

- name: Fetch ID Token
id: fetch-token
run: |
_ID_TOKEN=$(gcloud auth print-identity-token --impersonate-service-account=${{ secrets.GCP_SERVICE_ACCOUNT }} -q)
echo "::add-mask::${_ID_TOKEN}"
echo "_id_token=${_ID_TOKEN}" >> $GITHUB_OUTPUT

- name: Run load test
run: |
export _ID_TOKEN="${{ steps.fetch-token.outputs._id_token }}"
export _STAGING_URL="${{ steps.fetch-url.outputs._staging_url }}"
pip install locust==2.31.1
locust -f tests/load_test/load_test.py \
--headless \
-H ${_STAGING_URL} \
-t 30s -u 10 -r 0.5 \
--csv=tests/load_test/.results/results \
--html=tests/load_test/.results/report.html

- name: Export Load Test Results to GCS
run: |
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
gcloud storage cp --recursive tests/load_test/.results gs://${{ vars.LOGS_BUCKET_NAME_STAGING }}/load-test-results/results-${TIMESTAMP} --quiet
echo "_________________________________________________________________________"
echo "Load test results copied to gs://${{ vars.LOGS_BUCKET_NAME_STAGING }}/load-test-results/results-${TIMESTAMP}"
echo "HTTP link: https://console.cloud.google.com/storage/browser/${{ vars.LOGS_BUCKET_NAME_STAGING }}/load-test-results/results-${TIMESTAMP}"
echo "_________________________________________________________________________"

call_production_workflow:
needs: deploy_and_test_staging
uses: ./.github/workflows/deploy-to-prod.yaml
permissions:
contents: 'read'
id-token: 'write'
secrets: inherit
Loading
Loading