streamline GEMINI file, drop agents rules (#3857)

This commit is contained in:
Ludovico Magnocavallo
2026-04-10 22:28:40 +02:00
committed by GitHub
parent 1e34ae3bc8
commit ebc4669b4d
8 changed files with 14 additions and 167 deletions

View File

@@ -1,48 +0,0 @@
---
trigger: always_on
---
# Context-Based Interpolation
When designing factory patterns or datasets, you MUST leverage the **context-based interpolation** system.
A `context` object variable is used to hold maps of known, existing resource IDs (such as `project_ids`, `folder_ids`, `networks`, `iam_principals`).
## Usage Pattern
1. **Variables:** Add a `context` variable in `variables.tf`.
```hcl
variable "context" {
description = "Context-specific interpolations."
type = object({
project_ids = optional(map(string), {})
folder_ids = optional(map(string), {})
})
default = {}
}
```
2. **Locals:** Build `ctx` and `ctx_p` local variables in `main.tf` by flattening the `var.context` object.
```hcl
locals {
ctx = {
for k, v in var.context : k => {
for kk, vv in v : "${local.ctx_p}${k}:${kk}" => vv
}
}
ctx_p = "$"
}
```
3. **Lookups:** Apply lookups inside resources.
```hcl
project = lookup(local.ctx.project_ids, var.project_id, var.project_id)
```
4. **YAML Interpolation:** In factory YAML files, use the `$` prefix convention to reference the lookup map keys.
```yaml
# Instead of hardcoding the folder ID: parent: folders/1234567890
parent: $folder_ids:teams/team-a
```
This pattern makes YAML configuration files highly portable across installations and environments by substituting mnemonic keys for hardcoded values.

View File

@@ -1,13 +0,0 @@
---
trigger: always_on
---
# Always make sure edited code passes linting checks
- run `tools/tfdoc.py` if variable or output definitions changed
- run `tools/check_documentation.py` to ensure variables are sorted alphabetically and READMEs are consistent
- run `tools/check_boilerplate.py` to ensure license headers are present
- run `terraform fmt` on any edited Terraform file, and hcl examples in README files
- run `yamllint -c .yamllint --no-warnings <yaml-files>` on any edited YAML files
- a schema change should be reflected in all the other places that use the same schema, those are documented in `tools/duplicate-diff.py`
- always make sure both example and module (or stage) level tests run for all the modules/stages where code was edited

View File

@@ -1,18 +0,0 @@
---
trigger: always_on
---
# Use factory datasets for resource configuration
**FAST stages should leverage module-backed factories (e.g., `project-factory`) when available, but must implement their own stage-level factories when macro-modules don't exist.**
Stages in the FAST folder are split between Terraform code and datasets.
Code is used to implement and wire together "factories" that implement resource management, while the actual description of resources and their relationships is implemented via YAML configurations read by those factories.
- YAML configurations are grouped in "datasets" which implement a complete design for the stage
- each factory has a reference JSON schema used to describe and validate the YAML data
- factories are generally implemented in the underlying modules, not in FAST stages, *unless* the stage needs to iterate over standard modules or resources (e.g., `dns` zones, `net-firewall-policy`, `ncc_hubs`).
- modules deal with one specific resource set (eg an instance and its disks, a project and its org policies, IAM, etc.) and generally implement a single factory
- the project and VPC factory modules are the exception, as they are designed as "macro modules" to support interrelated creation of resources pertaining to a larger scope
- modules that do not manage "sets" of resources (e.g. one project, one folder, one dataset, etc.) typically do not have an associated factory, or only do for sub-resources (e.g. rules in a single policy), those factories are either implemented in the "macro modules" or directly in FAST

View File

@@ -1,9 +0,0 @@
---
trigger: always_on
---
Modules are designed to be containers for all aspects related to uage of a resource type. The pattern is a module is focused on a specific resource (e.g. folder, project, vpc, etc.) and implements all the functionality needed to create/manage that resources so that it is ready for user consumption. This includes: IAM, sub resources (eg subnets and routes for a network), org policies where applicable, etc.
Unrelated resources like a dataset for a project should never be part of the same module, except in the two "aggregation modules" (project and vpc factory) where that makes sense to allow consumers to create baseline infrastructure ready to receive application-level resources.
Never, ever break this boundary as a first approach, and always, always check in with the user if this looks like the only plan of action, as the criteria and constraints that led to the plan might need to be revised instead.

View File

@@ -1,27 +0,0 @@
---
trigger: always_on
---
# Strictly Adhere to the Fabric Style Guide
When modifying or generating Terraform code, you MUST follow these specific style conventions:
- **Line Length:** Enforce a 79-character line length limit for legibility. This rule is relaxed *only* for long resource attribute names and descriptions.
- **Ternary Operators:** Wrap complex ternary operators in parentheses and break lines to align the `?` and `:` tokens clearly. Example:
```hcl
locals {
parent_id = (
var.parent == null || startswith(coalesce(var.parent, "-"), "$")
? var.parent
: split("/", var.parent)[1]
)
}
```
- **Function Calls:** Split function calls with many arguments across multiple lines, typically breaking after the opening parenthesis and before the closing one.
- **Alphabetical Ordering:** You MUST ensure variables and outputs are strictly sorted alphabetically. Run `tools/check_documentation.py` to verify this.
- **Locals Separation:**
- Use module-level locals for values referenced directly by resources or outputs (e.g., `svpc_host_config`).
- Use block-level "private" locals prefixed with an underscore (`_`) for intermediate transformations only referenced within the same block (e.g., `_svpc_service_iam`).
- **Complex Transformations:** Move complex data transformations in `for` or `for_each` loops to `locals` to keep resource blocks clean.
- **Variable Spaces:** Leverage `optional()` defaults extensively within object variables to reduce verbosity.
- **Naming:** NEVER use random strings for resource naming. Instead, implement and use an optional `prefix` variable in all modules.

View File

@@ -1,31 +0,0 @@
---
trigger: always_on
---
# Use Example-Based Testing in README.md
When testing modules, you MUST prefer example-based testing over writing legacy Python `pytest` functions.
Example-based tests are triggered from HCL Markdown fenced code blocks inside a module's `README.md` file using a special `# tftest` comment at the bottom.
## How to structure a test
1. Write a clear HCL code block demonstrating the functionality.
2. Add the `tftest` directive, declaring expected counts.
3. If validating values, point to a YAML inventory file.
```hcl
module "my-module" {
source = "./modules/my-module"
name = "test-example"
}
# tftest modules=1 resources=2 inventory=my-inventory.yaml
```
## Inventory Files
Inventory files are YAML datasets used to assert that the generated plan matches expectations.
- Place them in the `tests/modules/<module_name>/examples/` directory.
- You can generate an inventory automatically by running a successful plan using `pytest -s` (refer to `CONTRIBUTING.md` for the exact command format).
- **DO NOT hand-code inventory files from scratch.** Extract only the necessary bits relevant to the test scenario from the generated output.
## tftest-based tests (Advanced)
If a module lacks an example in its `README.md` or you are testing a FAST stage without examples, use `tftest`-based tests using `tfvars` and `yaml` files. Refer to the "Testing via `tfvars` and `yaml`" section in `CONTRIBUTING.md`.

View File

@@ -11,7 +11,8 @@ Cloud Foundation Fabric is a comprehensive suite of Terraform modules and end-to
### 1. Modules (`/modules`) ### 1. Modules (`/modules`)
* **Philosophy:** Lean, composable, and close to the underlying provider resources. * **Philosophy:** Lean, composable, and close to the underlying provider resources. Modules are designed to be containers for all aspects related to usage of a resource type (e.g., folder, project, vpc, etc.). This includes IAM, sub-resources (e.g. subnets and routes for a network), and org policies where applicable.
* **Boundary:** Unrelated resources (like a dataset for a project) should never be part of the same module, except in the two "aggregation modules" (`project-factory` and `net-vpc-factory`). Never break this boundary as a first approach.
* **Structure:** * **Structure:**
* Standardized interfaces: IAM, logging, organization policies, etc. * Standardized interfaces: IAM, logging, organization policies, etc.
* Self-contained: Dependency injection via context variables is preferred over complex remote state lookups within modules. * Self-contained: Dependency injection via context variables is preferred over complex remote state lookups within modules.
@@ -25,7 +26,7 @@ Cloud Foundation Fabric is a comprehensive suite of Terraform modules and end-to
* **Purpose:** Rapidly set up a secure, scalable GCP organization. * **Purpose:** Rapidly set up a secure, scalable GCP organization.
* **Architecture:** Divided into sequential "stages" (0-org-setup, 1-vpcsc, 2-security, 2-networking, etc.). * **Architecture:** Divided into sequential "stages" (0-org-setup, 1-vpcsc, 2-security, 2-networking, etc.).
* **Factories:** Extensively uses YAML-based datasets and module factory patterns to drive configuration at scale, acting as a "translation machine" that expresses different architectural designs without changing the underlying stage code. * **Factories:** Extensively uses YAML-based datasets and module factory patterns to drive configuration at scale, acting as a "translation machine" that expresses different architectural designs without changing the underlying stage code. Factories are generally implemented in the underlying modules, not in FAST stages, *unless* the stage needs to iterate over standard modules or resources (e.g., `dns` zones, `net-firewall-policy`, `ncc_hubs`).
### 3. Tools (`/tools`) ### 3. Tools (`/tools`)
@@ -64,6 +65,8 @@ python3 tools/check_documentation.py modules/<module-name>
# Regenerate README variables/outputs tables when check fails # Regenerate README variables/outputs tables when check fails
# Note: tfdoc uses special HTML comments (<!-- BEGIN TFDOC -->) in READMEs. Do not manually edit these sections. # Note: tfdoc uses special HTML comments (<!-- BEGIN TFDOC -->) in READMEs. Do not manually edit these sections.
# You can configure tfdoc via HTML comments in the README (e.g., <!-- TFDOC OPTS files:1 show_extra:1 -->).
# To add a file description to the generated table, use a comment in the .tf file: # tfdoc:file:description My description.
python3 tools/tfdoc.py --replace modules/<module-name> python3 tools/tfdoc.py --replace modules/<module-name>
# YAML linting # YAML linting
@@ -71,6 +74,10 @@ yamllint -c .yamllint --no-warnings <yaml-files>
# License/boilerplate check # License/boilerplate check
python3 tools/check_boilerplate.py --scan-files <files> python3 tools/check_boilerplate.py --scan-files <files>
# Schema changes
# A schema change should be reflected in all the other places that use the same schema.
# These are documented in and can be checked via tools/duplicate-diff.py.
``` ```
**Common gotcha — unsorted variables (`[SV]` error):** `check_documentation.py` requires variables in `variables.tf` to be in strict alphabetical order. When adding a new variable, insert it at the correct alphabetical position, not at the top of the file. **Common gotcha — unsorted variables (`[SV]` error):** `check_documentation.py` requires variables in `variables.tf` to be in strict alphabetical order. When adding a new variable, insert it at the correct alphabetical position, not at the top of the file.
@@ -89,7 +96,9 @@ module "my-module" {
# tftest modules=1 resources=2 inventory=my-inventory.yaml # tftest modules=1 resources=2 inventory=my-inventory.yaml
``` ```
* **Inventory files (`YAML`):** Used to assert specific values, resource counts, or outputs from the terraform plan against an expected dataset. * **Inventory files (`YAML`):** Used to assert specific values, resource counts, or outputs from the terraform plan against an expected dataset. **DO NOT hand-code inventory files from scratch.** Extract only the necessary bits relevant to the test scenario from the generated output.
* **External Files:** If a README test requires external files (e.g., for factories), mock them using the `# tftest-file id=myid path=path/to/file.yaml` directive in a separate YAML block, and add `files=myid` to the `tftest` directive.
* **FAST Stages & `tftest.yaml`:** FAST stages often lack README examples. For these, use `tftest`-based tests by creating `tfvars` and `yaml` inventory pairs in `tests/fast/...` and tying them together with a `tftest.yaml` file.
* **Legacy Tests:** Python-based tests using `pytest` and `tftest` are supported but example-based tests should be used whenever possible. * **Legacy Tests:** Python-based tests using `pytest` and `tftest` are supported but example-based tests should be used whenever possible.
```bash ```bash
@@ -183,6 +192,8 @@ ip_address = (
) )
``` ```
**5. YAML Interpolation:** In factory YAML files, use the `$` prefix convention to reference the lookup map keys (e.g., `parent: $folder_ids:teams/team-a`).
### Tests ### Tests
Add a `context` test alongside existing module tests: Add a `context` test alongside existing module tests:
@@ -213,9 +224,3 @@ Modify one existing README example (do not add a new one) to demonstrate context
* **Locals Separation:** Use module-level locals for values referenced directly by resources/outputs. Use block-level "private" locals prefixed with an underscore (`_`) for intermediate transformations. * **Locals Separation:** Use module-level locals for values referenced directly by resources/outputs. Use block-level "private" locals prefixed with an underscore (`_`) for intermediate transformations.
* **Complex Transformations:** Move complex data transformations in `for` or `for_each` loops to `locals` to keep resource blocks clean. * **Complex Transformations:** Move complex data transformations in `for` or `for_each` loops to `locals` to keep resource blocks clean.
## Preferred Workflow
- Always break down complex requests into small, iterative tasks.
- For each task, propose the necessary edits and explicitly wait for user confirmation or discussion before proceeding.
- Always use the `replace` tool to both perform and cleanly display the proposed text modifications. Do not silently overwrite files or use shell commands for text edits.
- **CRITICAL:** NEVER use shell redirections (like `cat << 'EOF' > file` or `echo "text" > file`) or `sed`/`awk` scripts for editing files. Always use the `replace` tool for targeted edits or the `write_file` tool for new/small files.

View File

@@ -1,12 +0,0 @@
# Module testing notes
## Generating test inventory files
1. Specify `inventory=filename.yaml` in the `tftest` annotation in `README.md`.
2. Create the empty inventory file in `tests/modules/<module_name>/examples/` (note the underscore in module name, e.g., `compute_vm`).
3. Place the standard copyright blurb at the top.
4. Add `counts: { foo: 1 }` to the inventory file.
5. Run the specific test using `pytest "tests/examples/test_plan.py::test_example[terraform:modules/<module-name>:Heading Name:Index]"`.
6. Use the test failure output to replace `counts` with the actual resource types and counts.
7. Add `values: { foo: 1 }` to the inventory file and run the test again.
8. Use the output to replace `values` with the actual mapped attributes. Remove unnecessary or overly verbose keys like large instance configurations, and use `{}` for resources where specific values don't need validation.