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 contains no Twilio resources, provider configuration, 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, 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 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.
13 changes: 6 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,20 @@ init: clean
-backend-config="region=${S3_REGION}" \
-backend-config="use_lockfile=true"

# The encrypted file is verified and exposed only to this short-lived child
# process. It does not configure the Twilio provider or call Twilio APIs.
# 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.
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
@${TERRAFORM} plan -refresh=false -input=false -compact-warnings
@sops exec-env "${TWILIO_CREDENTIALS}" '${TERRAFORM} plan -refresh=false -input=false -compact-warnings'

# There are intentionally no provider configurations or Twilio resources in
# this root, so backend selection and encrypted-credential validation are the
# only stateful behaviors on main.
# This root has no Twilio resources. Provider authentication may perform its
# own read-only validation, but apply has no Twilio resource action to perform.
apply: init credentials-check
@${TERRAFORM} apply -auto-approve -refresh=false -input=false -compact-warnings
@sops exec-env "${TWILIO_CREDENTIALS}" '${TERRAFORM} apply -auto-approve -refresh=false -input=false -compact-warnings'

test: pre-commit-config pre-commit-install-hooks
@pre-commit run -a
Expand Down
14 changes: 8 additions & 6 deletions docs/bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@

## Scope

This root validates the OpenTofu toolchain, remote state backend, and encrypted provider-credential delivery 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 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.

The evaluated provider is `RJPearson94/twilio` `0.27.1`. Registry documentation confirms it supports Twilio phone-number resources and inbound `messaging` webhook fields, but it is community-maintained and requires existing account credentials. The root intentionally declares no provider configuration, so CI validates SOPS credential delivery without performing a provider-side API call.
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.

## Ownership boundary
## Intended message flow

The future root may own only Twilio phone-number inventory and inbound messaging-webhook configuration. `kustomize-cluster` remains the owner of the OpenCode bridge workload, workload `TunnelBinding`/DNS, fixed number-to-agent map, approved-source allowlist, runtime secrets, and runtime-encryption inputs. The root must never create a bridge-worker API key or duplicate a runtime owner.
The owner’s 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 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.

## Backend and credential contract

[`tfroot-aws` PR #43](https://github.com/makeitworkcloud/tfroot-aws/pull/43) created the canonical backend producer: a dedicated private, encrypted, versioned bucket and an exact-repository GitHub OIDC role restricted to the state object, lockfile, and SOPS KMS decrypt/describe access. This root selects that backend through the reusable workflow's `aws-role-to-assume` input and uses S3 native locking. No static AWS backend credential is stored in source or GitHub Actions secrets.

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 use `sops exec-env` to assert the three variables in a short-lived child process. They never write plaintext files, set static provider attributes, or use GitHub Actions secrets. The older `secrets/twilio.sops.env.example` placeholder is superseded and must not be used.
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.

Only after the encrypted credential path passes pull-request validation may a later root change add provider configuration or Twilio inventory. Any actual Twilio provisioning or webhook update still requires explicit owner confirmation before merge because `main` invokes the environment-gated apply path.
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.

## Central generated files

Expand Down
5 changes: 3 additions & 2 deletions providers.tf
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ terraform {
}
}

# No provider block is declared. The selected backend is independent of Twilio
# credentials and resource management; those remain separate follow-up gates.
# Authentication is supplied only through TWILIO_ACCOUNT_SID, TWILIO_API_KEY,
# and TWILIO_API_SECRET in SOPS exec-env. Do not add static credentials here.
provider "twilio" {}
Loading