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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ OpenTofu root for Make IT Work Cloud Twilio control-plane infrastructure.

This root owns only Twilio phone-number inventory and inbound messaging-webhook configuration. It must not own the OpenCode SMS bridge workload, Cloudflare workload route or DNS, number-to-agent mapping, approved-source allowlist, bridge credentials, or runtime encryption material. Those runtime concerns belong to `kustomize-cluster`.

The root owns the SOPS-encrypted `secrets/secrets.yaml` provider credential file and no other secret material. It contains only the Twilio provider environment-variable names. The root configures the Twilio provider exclusively from those process-scoped environment variables, but contains no Twilio resources, state, or number identifiers. Use GitHub MCP and pull-request CI plans as validation authority. `main` is an environment-gated apply path; use scoped branches and pull requests, never direct pushes. Do not run OpenTofu, SOPS, state, import, or apply commands from this server.
The root owns the SOPS-encrypted `secrets/secrets.yaml` provider credential file and no other secret material. It contains only the Twilio provider environment-variable names. The root configures the Twilio provider exclusively from those process-scoped environment variables and passes the account SID to declared resources only as `TF_VAR_account_sid` inside the same SOPS `exec-env` child. `numbers.tf` declares the four pilot phone-number resources; purchased number values live only in remote state and outputs. Use GitHub MCP and pull-request CI plans as validation authority. `main` is an environment-gated apply path; use scoped branches and pull requests, never direct pushes. Do not run OpenTofu, SOPS, state, import, or apply commands from this server.

The shared workflow is owned by `shared-workflows`; the runner image and canonical pre-commit configuration are owned by `images/tfroot-runner`. Keep any future SOPS data encrypted and never expose credentials, decrypted values, state, private keys, or sensitive plans.
9 changes: 5 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,19 @@ init: clean

# Verify ciphertext and required keys without printing values. plan and apply run
# OpenTofu inside a separate SOPS exec-env child so the provider can authenticate.
# The account SID reaches OpenTofu only as TF_VAR_account_sid inside that child.
credentials-check:
@test -f "${TWILIO_CREDENTIALS}"
@sops filestatus "${TWILIO_CREDENTIALS}" | jq -e '.encrypted == true' >/dev/null
@sops exec-env "${TWILIO_CREDENTIALS}" 'test -n "$$TWILIO_ACCOUNT_SID" && test -n "$$TWILIO_API_KEY" && test -n "$$TWILIO_API_SECRET"'

plan: init credentials-check
@sops exec-env "${TWILIO_CREDENTIALS}" '${TERRAFORM} plan -refresh=false -input=false -compact-warnings'
@sops exec-env "${TWILIO_CREDENTIALS}" 'TF_VAR_account_sid="$$TWILIO_ACCOUNT_SID" ${TERRAFORM} plan -refresh=false -input=false -compact-warnings'

# This root has no Twilio resources. Provider authentication may perform its
# own read-only validation, but apply has no Twilio resource action to perform.
# The four twilio_phone_number.agent resources purchase pilot numbers on apply.
# No inbound webhook field is set until the bridge is deployed and healthy.
apply: init credentials-check
@sops exec-env "${TWILIO_CREDENTIALS}" '${TERRAFORM} apply -auto-approve -refresh=false -input=false -compact-warnings'
@sops exec-env "${TWILIO_CREDENTIALS}" 'TF_VAR_account_sid="$$TWILIO_ACCOUNT_SID" ${TERRAFORM} apply -auto-approve -refresh=false -input=false -compact-warnings'

test: pre-commit-config pre-commit-install-hooks
@pre-commit run -a
Expand Down
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,29 @@

## Providers

No providers.
| Name | Version |
| ---- | ------- |
| <a name="provider_twilio"></a> [twilio](#provider\_twilio) | 0.27.1 |

## Modules

No modules.

## Resources

No resources.
| Name | Type |
| ---- | ---- |
| [twilio_phone_number.agent](https://registry.terraform.io/providers/RJPearson94/twilio/0.27.1/docs/resources/phone_number) | resource |

## Inputs

No inputs.
| Name | Description | Type | Default | Required |
| ---- | ----------- | ---- | ------- | :------: |
| <a name="input_account_sid"></a> [account\_sid](#input\_account\_sid) | Twilio account SID, supplied only from SOPS exec-env through TF\_VAR\_account\_sid. | `string` | n/a | yes |

## Outputs

No outputs.
| Name | Description |
| ---- | ----------- |
| <a name="output_agent_phone_numbers"></a> [agent\_phone\_numbers](#output\_agent\_phone\_numbers) | Purchased pilot number for each primary agent. |
<!-- END_TF_DOCS -->
12 changes: 7 additions & 5 deletions docs/bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

## Scope

This root validates the OpenTofu toolchain, remote state backend, encrypted provider-credential delivery, and Twilio provider authentication only. It creates, imports, updates, or deletes **no** Twilio resources. In particular, it does not purchase or configure phone numbers, webhooks, messaging services, or runtime routing.
This root validates the OpenTofu toolchain, remote state backend, encrypted provider-credential delivery, and Twilio provider authentication. It now also owns the pilot phone-number inventory: exactly one purchased US local SMS/MMS-capable number per primary agent (`lawnmowerman`, `grillmaster`, `homesteader`, `homerepair`), declared in `numbers.tf`.

The evaluated provider is `RJPearson94/twilio` `0.27.1`. It is community-maintained and requires existing account credentials. The provider is intentionally configured with no static attributes: OpenTofu receives its credentials only in a SOPS `exec-env` child. Its authentication validation may perform a read-only Twilio API request; no resource is declared or changed by this root.
It configures **no** inbound messaging webhook. The `messaging` block on each number is added only in a separately reviewed change after the `kustomize-cluster` bridge is reconciled, healthy, and explicitly approved for functional testing. The root does not own the bridge workload, Cloudflare workload route or DNS, number-to-agent mapping, approved-source allowlist, bridge credentials, or runtime encryption material; those runtime concerns belong to `kustomize-cluster`.

The evaluated provider is `RJPearson94/twilio` `0.27.1`. The provider is intentionally configured with no static attributes: OpenTofu receives its credentials only in a SOPS `exec-env` child, and the resource `account_sid` reaches OpenTofu only as `TF_VAR_account_sid` inside that same child process. The purchased number values live only in remote state and the `agent_phone_numbers` output.

## Intended message flow

The owners intended outcome is one Twilio phone number for each primary agent: `lawnmowerman`, `grillmaster`, `homesteader`, and `homerepair`. Each number will initially accept inbound SMS/MMS only from the one owner-approved source phone number, then route the request to its corresponding agent for a timely reply using that agents existing context, knowledge base, and MCP integrations. The sender allowlist is intentionally extensible: adding a further approved source number after the pilot is a separate runtime-configuration change, not a Twilio-root redesign.
The owner's intended outcome is one Twilio phone number for each primary agent. Each number will initially accept inbound SMS/MMS only from the one owner-approved source phone number, then route the request to its corresponding agent for a timely reply using that agent's existing context, knowledge base, and MCP integrations. The sender allowlist is intentionally extensible: adding a further approved source number after the pilot is a separate runtime-configuration change, not a Twilio-root redesign.

`kustomize-cluster` exclusively owns the bridge workload, number-to-agent map, sender allowlist and its later expansion, runtime secrets, `TunnelBinding`/DNS, and public route. This root may later own only the Twilio number inventory and the inbound messaging-webhook fields pointing at the already-healthy bridge. It must not duplicate any bridge/runtime configuration.

Expand All @@ -18,8 +20,8 @@ The owner’s intended outcome is one Twilio phone number for each primary agent

The checked-in `.sops.yaml` identifies the approved encryption recipient. `secrets/secrets.yaml` is the only accepted provider credential file. It holds the encrypted `TWILIO_ACCOUNT_SID`, `TWILIO_API_KEY`, and `TWILIO_API_SECRET` values; it must never contain bridge runtime inputs. `make plan` and `make apply` first require SOPS to recognize the file as encrypted, then run OpenTofu inside `sops exec-env`. They never write plaintext files, set static provider attributes, or use GitHub Actions secrets.

This provider-only change must pass pull-request validation before later Twilio inventory or webhook work is proposed. Any actual Twilio provisioning or webhook update still requires explicit owner confirmation before merge because `main` invokes the environment-gated apply path.
Any change that purchases numbers or updates a webhook requires explicit owner confirmation before merge because `main` invokes the environment-gated apply path.

## Central generated files

`.github/dependabot.yml` and `.github/workflows/dependabot-notify.yml` are seeded here with the exact content generated by `tfroot-github`. They are not locally owned. This PR-based seed resolves the branch-protection bootstrap conflict; after merge, the central `github_repository_file` resources can adopt and continue managing them with `overwrite_on_create = true`.
`.github/dependabot.yml` and `.github/workflows/dependabot-notify.yml` are centrally generated by `tfroot-github`. They are not locally owned; do not hand-edit them.
39 changes: 39 additions & 0 deletions numbers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# One pilot number per primary agent. Purchased US local numbers with SMS
# and MMS capability; no inbound webhook is configured here. The messaging
# webhook is added only after the kustomize-cluster bridge is healthy.

variable "account_sid" {
type = string
description = "Twilio account SID, supplied only from SOPS exec-env through TF_VAR_account_sid."
}

locals {
agent_numbers = {
lawnmowerman = "opencode-sms lawnmowerman"
grillmaster = "opencode-sms grillmaster"
homesteader = "opencode-sms homesteader"
homerepair = "opencode-sms homerepair"
}
}

resource "twilio_phone_number" "agent" {
for_each = local.agent_numbers

account_sid = var.account_sid
friendly_name = each.value

search_criteria {
iso_country = "US"
type = "local"

capabilities {
sms_enabled = true
mms_enabled = true
}
}
}

output "agent_phone_numbers" {
description = "Purchased pilot number for each primary agent."
value = { for name, number in twilio_phone_number.agent : name => number.phone_number }
}
Loading