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
80 changes: 80 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

permissions:
contents: read

jobs:
hcl-lint:
name: HCL Lint (TFLint)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup TFLint
uses: terraform-linters/setup-tflint@v4

- name: Run TFLint recursively
run: |
set -euo pipefail
cd terraform
tflint --init
tflint --recursive

bash-lint:
name: Bash Lint (ShellCheck)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install ShellCheck
run: |
sudo apt-get update
sudo apt-get install -y shellcheck

- name: Run ShellCheck on shell scripts and .envrc
run: |
set -euo pipefail
mapfile -d '' shell_files < <(find . -type f \( -name "*.sh" -o -name "*.bash" \) -not -path "./.git/*" -print0)
mapfile -d '' envrc_files < <(find . -type f -name ".envrc" -not -path "./.git/*" -print0)

if [ "${#shell_files[@]}" -gt 0 ]; then
shellcheck -x -S error "${shell_files[@]}"
fi

if [ "${#envrc_files[@]}" -gt 0 ]; then
shellcheck -s bash -S error "${envrc_files[@]}"
fi

if [ "${#shell_files[@]}" -eq 0 ] && [ "${#envrc_files[@]}" -eq 0 ]; then
echo "No shell files or .envrc found."
fi

python-lint:
name: Python Lint (Ruff)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.x"

- name: Install Ruff
run: python -m pip install --upgrade ruff

- name: Run Ruff
run: |
set -euo pipefail
ruff check .
5 changes: 3 additions & 2 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,10 @@ jobs:
- name: Run Checkov on Terraform
uses: bridgecrewio/checkov-action@v12
with:
directory: terraform/digitalOcean
directory: terraform
framework: terraform
skip_check: CKV_DIO_4
# Keep selected checks skipped for direct-access and low-ops deployment targets.
skip_check: CKV_DIO_4,CKV_AZURE_119,CKV_GCP_40,CKV_AZURE_50,CKV_GCP_62,CKV_GCP_84,CKV_GCP_38
quiet: true
output_format: cli,sarif
output_file_path: console,checkov.sarif
Expand Down
5 changes: 5 additions & 0 deletions terraform/azure_vm/security.tf
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,8 @@ resource "azurerm_network_interface_security_group_association" "main" {
network_interface_id = azurerm_network_interface.main.id
network_security_group_id = azurerm_network_security_group.main.id
}

resource "azurerm_subnet_network_security_group_association" "internal" {
subnet_id = azurerm_subnet.internal.id
network_security_group_id = azurerm_network_security_group.main.id
}
15 changes: 10 additions & 5 deletions terraform/azure_vm/variables.tf
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
# ── Azure Authentication ────────────────────────────────────
# These come from terraform.tfvars
variable "subscription_id" {
type = string
sensitive = true
}

variable "client_id" {
type = string
sensitive = true
}

variable "client_secret" {
type = string
sensitive = true
}

variable "tenant_id" {
type = string
sensitive = true
}

Expand Down Expand Up @@ -94,36 +98,37 @@ variable "openclaw_memory_limit_mb" {

# ── Secrets (from .env via .envrc) ─────────────────────────
variable "openrouter_api_key" {
type = string
sensitive = true
}

variable "telegram_bot_token" {
type = string
sensitive = true
}

variable "openclaw_gateway_token" {
type = string
sensitive = true
}

variable "brave_api_key" {
description = "Brave Search API key (free tier: 1000 req/month). Leave empty to use DuckDuckGo fallback."
type = string
sensitive = true
default = ""
}

variable "telegram_owner_id" {
description = "Your Telegram numeric user ID (get it from @userinfobot). Grants /model and other privileged commands."
default = ""
}

variable "slack_app_token" {
description = "Slack App-Level Token for Socket Mode connection (starts with 'xapp-')"
type = string
sensitive = true
default = ""
}

variable "slack_bot_token" {
description = "Slack Bot User OAuth Token for sending messages (starts with 'xoxb-')"
type = string
sensitive = true
default = ""
}
2 changes: 2 additions & 0 deletions terraform/digitalOcean/main.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
terraform {
required_version = ">= 1.5.0"

required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
Expand Down
12 changes: 12 additions & 0 deletions terraform/digitalOcean/variables.tf
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
# ── DigitalOcean Auth ────────────────────────────────────────
variable "do_token" {
type = string
sensitive = true
}

# ── SSH ──────────────────────────────────────────────────────
variable "ssh_public_key_path" {
description = "Path to your SSH public key, e.g. ~/.ssh/id_rsa.pub"
type = string
default = "~/.ssh/id_rsa.pub"
}

# ── Droplet ──────────────────────────────────────────────────
variable "region" {
description = "DigitalOcean region slug (e.g. tor1, sfo3, nyc3, sgp1, ams3)"
type = string
default = "tor1"
}

variable "droplet_size" {
description = "Droplet size slug (e.g. s-1vcpu-1gb=$6, s-1vcpu-2gb=$12, s-2vcpu-2gb=$18)"
type = string
default = "s-1vcpu-1gb"
}

Expand All @@ -34,41 +38,49 @@ variable "gateway_allowed_cidrs" {

variable "swap_size" {
description = "Swap file size (e.g. 2G, 3G, 4G) — prevents OOM during npm install"
type = string
default = "3G"
}

# ── Secrets ──────────────────────────────────────────────────
variable "openrouter_api_key" {
type = string
sensitive = true
}

variable "telegram_bot_token" {
type = string
sensitive = true
}

variable "openclaw_gateway_token" {
type = string
sensitive = true
}

variable "brave_api_key" {
description = "Brave Search API key (free tier: 1000 req/month). Leave empty to use DuckDuckGo fallback."
type = string
sensitive = true
default = ""
}

variable "telegram_owner_id" {
description = "Your Telegram numeric user ID (get it from @userinfobot). Grants /model and other privileged commands."
type = string
default = ""
}

variable "slack_app_token" {
description = "Slack App-Level Token for Socket Mode connection (starts with 'xapp-')"
type = string
sensitive = true
default = ""
}

variable "slack_bot_token" {
description = "Slack Bot User OAuth Token for sending messages (starts with 'xoxb-')"
type = string
sensitive = true
default = ""
}
5 changes: 5 additions & 0 deletions terraform/gcp_cloudrun/storage.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ resource "google_storage_bucket" "state" {
name = var.bucket_name
location = var.region
uniform_bucket_level_access = true
public_access_prevention = "enforced"
force_destroy = true

versioning {
enabled = true
}

depends_on = [google_project_service.required]
}

Expand Down
11 changes: 6 additions & 5 deletions terraform/gcp_cloudrun/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -70,34 +70,35 @@ variable "max_instances" {
}

variable "openrouter_api_key" {
type = string
sensitive = true
}

variable "telegram_bot_token" {
type = string
sensitive = true
}

variable "openclaw_gateway_token" {
type = string
sensitive = true
}

variable "brave_api_key" {
description = "Brave Search API key (optional)"
type = string
sensitive = true
default = ""
}

variable "telegram_owner_id" {
description = "Telegram numeric user ID for privileged commands"
default = ""
}

variable "slack_app_token" {
description = "Slack App-Level Token (xapp-...)"
type = string
sensitive = true
}

variable "slack_bot_token" {
description = "Slack Bot OAuth Token (xoxb-...)"
type = string
sensitive = true
}
9 changes: 8 additions & 1 deletion terraform/gcp_vm/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,14 @@ resource "google_compute_instance" "main" {
}

metadata = {
ssh-keys = local.ssh_key_entry
ssh-keys = local.ssh_key_entry
block-project-ssh-keys = "true"
}

shielded_instance_config {
enable_secure_boot = true
enable_vtpm = true
enable_integrity_monitoring = true
}

metadata_startup_script = templatefile("${path.module}/bootstrap.sh", local.bootstrap_vars)
Expand Down
11 changes: 6 additions & 5 deletions terraform/gcp_vm/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -83,36 +83,37 @@ variable "openclaw_memory_limit_mb" {
}

variable "openrouter_api_key" {
type = string
sensitive = true
}

variable "telegram_bot_token" {
type = string
sensitive = true
}

variable "openclaw_gateway_token" {
type = string
sensitive = true
}

variable "brave_api_key" {
description = "Brave Search API key (optional)"
type = string
sensitive = true
default = ""
}

variable "telegram_owner_id" {
description = "Telegram numeric user ID for privileged commands"
default = ""
}

variable "slack_app_token" {
description = "Slack App-Level Token (xapp-...)"
type = string
sensitive = true
default = ""
}

variable "slack_bot_token" {
description = "Slack Bot OAuth Token (xoxb-...)"
type = string
sensitive = true
default = ""
}
Loading