Compare commits

..
2 Commits
5 changed files with 36 additions and 33 deletions
+3
View File
@@ -9,3 +9,6 @@ tfplan*
# VS Code
.vscode/*
# Python
__pycache__/
+6 -6
View File
@@ -1,4 +1,4 @@
# Gemini Enterprise Agent Platform Terraform Scaffold
# Gemini Enterprise Agent Platform - Terraform Scaffold
Provisions the infrastructure needed to use the Gemini Enterprise Agent Platform (Vertex AI Agent Engine) on an existing GCP project: required APIs, service accounts, and IAM bindings.
@@ -14,7 +14,7 @@ Provisions the infrastructure needed to use the Gemini Enterprise Agent Platform
```bash
cp terraform.tfvars.example terraform.tfvars
# edit terraform.tfvars set your project_id
# edit terraform.tfvars - set your project_id
terraform init
terraform plan
@@ -25,7 +25,7 @@ terraform apply
| Name | Required | Default | Description |
|---|---|---|---|
| `project_id` | yes | | Existing GCP project ID |
| `project_id` | yes | - | Existing GCP project ID |
| `prefix` | no | `gemini` | Short prefix applied to all resource names |
## Outputs
@@ -39,7 +39,7 @@ terraform apply
## What gets created
- **7 GCP APIs** enabled (`aiplatform`, `cloudaicompanion`, `discoveryengine`, `dialogflow`, `secretmanager`, `iam`, `cloudresourcemanager`)
- **2 service accounts** one for app runtime, one for IDE enterprise config
- **2 service accounts** - one for app runtime, one for IDE enterprise config
- **4 project IAM bindings**
## Setting up credentials
@@ -51,7 +51,7 @@ gcloud auth application-default login
gcloud config set project <your-project-id>
```
For workloads running on GCP (Cloud Run, GKE, Compute Engine), attach the service account to the resource no credentials file needed.
For workloads running on GCP (Cloud Run, GKE, Compute Engine), attach the service account to the resource - no credentials file needed.
## Granting developer access to Gemini Code Assist
@@ -113,5 +113,5 @@ gcloud billing accounts list
## License
[MIT](LICENSE) © 2026 Slawomir Koszewski
[MIT](LICENSE) (c) 2026 Slawomir Koszewski
+20 -20
View File
@@ -196,16 +196,16 @@ def generate_report(
Guidelines:
- The list of changes above must be reproduced verbatim in the report under a "Planned Changes" section, preserving the grouping.
- Focus exclusively on what is changing and whether it is expected.
- Deletions and replacements are highest priority analyse each one individually: why might it be deleted or replaced, and is that intentional?
- Deletions and replacements are highest priority - analyse each one individually: why might it be deleted or replaced, and is that intentional?
- For updates and creates, note anything surprising in scope or naming.
- Do not include implementation advice the plan is already the product of implementation.
- Do not include implementation advice - the plan is already the product of implementation.
- Do not pad with generic statements.
Structure:
1. **Change Summary** one-paragraph overview of the overall scope
2. **Planned Changes** verbatim list from above
3. **Deletions & Replacements Analysis** only if any exist; individual analysis per resource
4. **Scope Review** does the set of changes look coherent and complete? flag anomalies"""
1. **Change Summary** - one-paragraph overview of the overall scope
2. **Planned Changes** - verbatim list from above
3. **Deletions & Replacements Analysis** - only if any exist; individual analysis per resource
4. **Scope Review** - does the set of changes look coherent and complete? flag anomalies"""
system_instruction = "You are a senior infrastructure engineer reviewing a Terraform plan before it is applied. Your job is to identify whether the changes match the deployment intent and surface anything worth scrutinising."
@@ -214,11 +214,11 @@ Structure:
from google import genai
from google.genai import types
except ImportError:
print("❌ Error: google-genai package is not installed. Please install it to use Gemini.", file=sys.stderr)
print("[ERROR] google-genai package is not installed. Please install it to use Gemini.", file=sys.stderr)
sys.exit(1)
if not gcp_project:
print("❌ Error: GCP project must be specified via --gcp-project or GOOGLE_CLOUD_PROJECT environment variable for Gemini.", file=sys.stderr)
print("[ERROR] GCP project must be specified via --gcp-project or GOOGLE_CLOUD_PROJECT environment variable for Gemini.", file=sys.stderr)
sys.exit(1)
client = genai.Client(vertexai=True, project=gcp_project, location=gcp_location)
@@ -339,36 +339,36 @@ def main():
plan_file = Path.cwd() / plan_file
if not plan_file.exists():
print(f"❌ Error: {plan_file} not found", file=sys.stderr)
print(f"[ERROR] {plan_file} not found", file=sys.stderr)
sys.exit(1)
print(f"📋 Loading plan from {plan_file}...", file=sys.stderr)
print(f"[INFO] Loading plan from {plan_file}...", file=sys.stderr)
plan = load_plan(plan_file)
print("🔍 Extracting resource changes...", file=sys.stderr)
print("[INFO] Extracting resource changes...", file=sys.stderr)
categorised = extract_resource_changes(plan)
total = sum(len(v) for v in categorised.values())
if not categorised:
print("⚠️ No resource changes found in the plan", file=sys.stderr)
print("[WARN] No resource changes found in the plan", file=sys.stderr)
sys.exit(1)
for action in ACTION_ORDER:
count = len(categorised.get(action, []))
if count:
print(f" {ACTION_LABELS[action]}: {count}", file=sys.stderr)
print(f" Total changes: {total}", file=sys.stderr)
print(f"[OK] Total changes: {total}", file=sys.stderr)
# Generate report
if args.ai:
if args.gemini:
if args.model == MODEL_DEFAULT:
args.model = "gemini-2.5-flash"
print(f"🚀 Generating AI report with Gemini ({args.model})...", file=sys.stderr)
print(f"[INFO] Generating AI report with Gemini ({args.model})...", file=sys.stderr)
elif args.azure_endpoint:
print(f"🚀 Generating AI report with Azure OpenAI ({args.model})...", file=sys.stderr)
print(f"[INFO] Generating AI report with Azure OpenAI ({args.model})...", file=sys.stderr)
else:
print(f"🚀 Generating AI report with OpenAI endpoint ({args.model})...", file=sys.stderr)
print(f"[INFO] Generating AI report with OpenAI endpoint ({args.model})...", file=sys.stderr)
report_start = time.time()
report = generate_report(
@@ -384,9 +384,9 @@ def main():
args.gcp_location
)
report_elapsed = time.time() - report_start
print(f" Completed in {report_elapsed:.2f}s", file=sys.stderr)
print(f" [OK] Completed in {report_elapsed:.2f}s", file=sys.stderr)
else:
print("📄 Generating plain report...", file=sys.stderr)
print("[INFO] Generating plain report...", file=sys.stderr)
report = generate_plain_report(categorised, plan)
# Determine output filename
@@ -402,12 +402,12 @@ def main():
with open(output_file, "w") as f:
f.write(report)
print(f"📄 Report written to {output_file}", file=sys.stderr)
print(f"[INFO] Report written to {output_file}", file=sys.stderr)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n⚠️ Interrupted by user", file=sys.stderr)
print("\n[WARN] Interrupted by user", file=sys.stderr)
sys.exit(1)
+6 -6
View File
@@ -1,6 +1,6 @@
#
# ---------------------------------------------
# 1. API Enablement
#
# ---------------------------------------------
locals {
apis = toset([
@@ -24,9 +24,9 @@ resource "google_project_service" "apis" {
disable_dependent_services = false
}
#
# ---------------------------------------------
# 2. Service Accounts
#
# ---------------------------------------------
resource "google_service_account" "agent_sa" {
project = var.project_id
@@ -46,9 +46,9 @@ resource "google_service_account" "code_assist_sa" {
depends_on = [google_project_service.apis]
}
#
# ---------------------------------------------
# 3. Project-level IAM Bindings (additive)
#
# ---------------------------------------------
resource "google_project_iam_member" "agent_sa_aiplatform_user" {
project = var.project_id
+1 -1
View File
@@ -1,5 +1,5 @@
# Copy this file to terraform.tfvars and fill in your values.
# terraform.tfvars is excluded from git (see .gitignore).
project_id = "your-gcp-project-id" # required your existing GCP project
project_id = "your-gcp-project-id" # required - your existing GCP project
prefix = "gemini" # optional, default: gemini