diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c761ace..10b315a 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,7 +10,7 @@ concurrency: cancel-in-progress: false permissions: - contents: read + contents: write id-token: write packages: write pull-requests: write @@ -205,3 +205,20 @@ jobs: -auto-approve \ -var-file=${{ steps.paths.outputs.TFVARS }} \ -input=false + + - name: Update GitHub Repo Description with Frontend URL (prod only) + if: github.ref == 'refs/heads/main' + run: | + cd terraform-infra + FRONTEND_URL=$(terraform output -raw app_engine_url 2>/dev/null || echo "") + if [ -n "$FRONTEND_URL" ]; then + echo "Updating GitHub repo description with URL: $FRONTEND_URL" + gh api repos/${{ github.repository }} \ + --method PATCH \ + -f homepage="$FRONTEND_URL" \ + -f description="Guidon - Serverless Discord Bot for collaborative drawing | Frontend: $FRONTEND_URL" + else + echo "Frontend URL not found in Terraform outputs, skipping update" + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/services/canvas-service/shared/auth_utils.py b/services/canvas-service/shared/auth_utils.py index 844501a..8e24b8e 100644 --- a/services/canvas-service/shared/auth_utils.py +++ b/services/canvas-service/shared/auth_utils.py @@ -14,28 +14,14 @@ def get_service_url_from_request(request: Request) -> Optional[str]: request: Flask request object Returns: - Full service URL including function path for Cloud Functions - (e.g., https://region-project.cloudfunctions.net/function-name) - or Cloud Run URL (e.g., https://service-name-xxx.a.run.app) + Full service URL (e.g., https://service-name-xxx.a.run.app) or None """ host = request.headers.get('Host') if host: scheme = request.headers.get('X-Forwarded-Proto', 'https') if ':' in host: host = host.split(':')[0] - - base_url = f"{scheme}://{host}" - - # For Cloud Functions Gen2, include the function name (first path segment) - # Request path like: /function-name/api/endpoint - # We want: https://domain.cloudfunctions.net/function-name - if 'cloudfunctions.net' in host and request.path: - path_parts = request.path.strip('/').split('/') - if path_parts and path_parts[0]: - # First segment is the function name - base_url = f"{base_url}/{path_parts[0]}" - - return base_url + return f"{scheme}://{host}" return None diff --git a/services/shared/auth_utils.py b/services/shared/auth_utils.py index 844501a..8e24b8e 100644 --- a/services/shared/auth_utils.py +++ b/services/shared/auth_utils.py @@ -14,28 +14,14 @@ def get_service_url_from_request(request: Request) -> Optional[str]: request: Flask request object Returns: - Full service URL including function path for Cloud Functions - (e.g., https://region-project.cloudfunctions.net/function-name) - or Cloud Run URL (e.g., https://service-name-xxx.a.run.app) + Full service URL (e.g., https://service-name-xxx.a.run.app) or None """ host = request.headers.get('Host') if host: scheme = request.headers.get('X-Forwarded-Proto', 'https') if ':' in host: host = host.split(':')[0] - - base_url = f"{scheme}://{host}" - - # For Cloud Functions Gen2, include the function name (first path segment) - # Request path like: /function-name/api/endpoint - # We want: https://domain.cloudfunctions.net/function-name - if 'cloudfunctions.net' in host and request.path: - path_parts = request.path.strip('/').split('/') - if path_parts and path_parts[0]: - # First segment is the function name - base_url = f"{base_url}/{path_parts[0]}" - - return base_url + return f"{scheme}://{host}" return None diff --git a/services/user-manager/shared/auth_utils.py b/services/user-manager/shared/auth_utils.py index 844501a..8e24b8e 100644 --- a/services/user-manager/shared/auth_utils.py +++ b/services/user-manager/shared/auth_utils.py @@ -14,28 +14,14 @@ def get_service_url_from_request(request: Request) -> Optional[str]: request: Flask request object Returns: - Full service URL including function path for Cloud Functions - (e.g., https://region-project.cloudfunctions.net/function-name) - or Cloud Run URL (e.g., https://service-name-xxx.a.run.app) + Full service URL (e.g., https://service-name-xxx.a.run.app) or None """ host = request.headers.get('Host') if host: scheme = request.headers.get('X-Forwarded-Proto', 'https') if ':' in host: host = host.split(':')[0] - - base_url = f"{scheme}://{host}" - - # For Cloud Functions Gen2, include the function name (first path segment) - # Request path like: /function-name/api/endpoint - # We want: https://domain.cloudfunctions.net/function-name - if 'cloudfunctions.net' in host and request.path: - path_parts = request.path.strip('/').split('/') - if path_parts and path_parts[0]: - # First segment is the function name - base_url = f"{base_url}/{path_parts[0]}" - - return base_url + return f"{scheme}://{host}" return None diff --git a/terraform-infra/main.tf b/terraform-infra/main.tf index 76adb97..79be8b3 100644 --- a/terraform-infra/main.tf +++ b/terraform-infra/main.tf @@ -423,6 +423,15 @@ resource "google_secret_manager_secret_iam_member" "gcs_bucket_access" { depends_on = [module.service_accounts] } +# Permissions IAM pour le service account cloud-functions sur le bucket canvas-snapshots +resource "google_storage_bucket_iam_member" "canvas_bucket_admin" { + bucket = module.gcs_buckets["canvas-snapshots"].bucket_name + role = "roles/storage.objectAdmin" + member = module.service_accounts["cloud-functions"].member + + depends_on = [module.gcs_buckets, module.service_accounts] +} + # ============================================================================ # PHASE 1 : Secrets basés sur l'API Gateway (valeurs temporaires) # ============================================================================ @@ -562,4 +571,28 @@ resource "google_secret_manager_secret_iam_member" "gcp_project_id_access" { member = module.service_accounts["cloud-functions"].member depends_on = [module.service_accounts] +} + +# ======================================== +# OUTPUTS +# ======================================== + +output "api_gateway_url" { + description = "URL de l'API Gateway" + value = module.api_gateway.gateway_url +} + +output "app_engine_url" { + description = "URL du frontend App Engine" + value = module.app_engine.app_url +} + +output "project_id" { + description = "ID du projet GCP" + value = var.project_id +} + +output "region" { + description = "Région GCP" + value = var.region } \ No newline at end of file