google / google/stellar-engine
[Bug] modules/project and modules/iam-service-account silently truncate over-length IDs instead of failing, and the documented prefix limit of 7 characters now leaves zero margin (naming-convention.md still says 6)
- Dominant language
- HCL
- Stars
- 49
- Forks
- 20
- Avg merge
- 3d 14h
- Merged PRs (30d)
- 28
Description
## Bug Description
Two shared modules build their resource IDs by **truncating to 30 characters instead of failing**:
```
# modules/project/main.tf:64
project_id = trimsuffix(replace(substr("${local.prefix}${var.name}", 0, 30), "_", "-"), "-")
# modules/iam-service-account/main.tf:49
account_id = trimsuffix(replace(substr("${local.prefix}${local.name}", 0, 30), "_", "-"), "-")
```
An input that overruns the limit does not produce an error. It produces a **different resource than
the operator asked for**, with a silently shortened ID, and `terraform apply` reports success. For a
project this is not recoverable by editing the tfvars afterwards: project IDs can never be reused, so
the shortened ID is permanent for the life of that project.
Today nothing in the shipped configuration overruns, but **the margin is exactly zero**, and the
documentation that tells operators how much room they have is no longer self-consistent.
### The margin is zero
The longest project ID the FAST stages generate is the tenant IaC core project,
`---iac-core-0`. With the maximum values the stages themselves validate:
| Input | Validated by | Max | Chars |
|---|---|---|---|
| `prefix` | `0-bootstrap/variables.tf:334` (`<= 7`), `1-resman/variables.tf:287` (`< 8`) | 7 | 7 |
| `--` | `envs_folders` keys, longest shipped is `Test` | — | 6 |
| `` | `1-resman/variables.tf:346` (`alltrue([for k, _ in var.tenants : length(k) < 7])`) | 6 | 6 |
| `-iac-core-0` | fixed | — | 11 |
| | | | **30** |
30 is exactly the Google Cloud project ID ceiling. Every one of those inputs is at its documented
maximum, so the configuration is legal — but there is no headroom at all, and the mechanism that
would catch the next increment is a `substr`, not a validation.
### The documented limit no longer agrees with itself
`v3.0.0` and PR #213 moved most of the prefix guidance to 7. One document did not move:
| Source | States |
|---|---|
| `fast/stages-aw/0-bootstrap/variables.tf:331` and `:335` | "Use 7 characters or less" / "Use a maximum of 7 characters for prefix." |
| `fast/stages-aw/0-bootstrap/README.md:133`, `:383` | 7 |
| `fast/stages-aw/0-bootstrap/terraform.tfvars.sample:30` | "Use something unique and no longer than 7 characters" |
| `docs/ddg.md:75`, `:221` | 7 (changed from 6 by PR #213) |
| **`docs/naming-convention.md:31`** | **"A short prefix of no more than 6 characters"** |
An operator following `naming-convention.md` and an operator following the DDG will size their prefix
differently, and only one of them is at the ceiling.
## Environment and Deployment Context
* **Stellar Engine Version/Commit:** `main` @ `6d7d08c0` (2026-09-09). The truncation in both modules is unchanged at `v2.13.0` (`8f5b67a6`) and `v3.0.0` (`f64ce6cd`); the documentation split is new since PR #213 (`1ce9c3f3`, merged 2026-09-05).
* **Deployment Type:**
* [ ] US Region Restricted (e.g., Access Policy constraint)
* [x] FedRAMP Moderate
* [x] FedRAMP High
* [x] DoD IL4
* [x] DoD IL5
* [x] Stand-alone / Custom
* **FAST Stage (if applicable):** shared modules, reached from every stage; the zero-margin case is Stage 1
* [x] Stage 0 (Bootstrap)
* [x] Stage 1 (Resource Management)
* [ ] Stage 2 (Networking)
* [ ] Stage 3 (Security)
## Steps to Reproduce
1. Set `prefix` to any 7-character value in `fast/stages-aw/0-bootstrap/terraform.tfvars`.
2. In `1-resman`, declare a tenant whose key is 6 characters (for example `report`) with `envs_folders` including `Test`.
3. `terraform plan` Stage 1 and read the planned tenant IaC core project ID: it is exactly 30 characters.
4. Now shorten nothing and lengthen one fixed part — for example add any suffix to `var.name` for that project in `modules/project`, or imagine a future context token. The plan does not fail; it plans a **shortened** project ID.
## Expected Behavior
An ID that does not fit should stop the plan with a message naming the input that is too long, the same way `prefix` and `tenants` already do. Where truncation is deliberate, the documented limits should leave enough room that it cannot be reached by a legal combination of inputs. `docs/naming-convention.md` should state the same prefix limit as the DDG, the variable description and the sample.
## Actual Behavior
`substr(..., 0, 30)` shortens the ID silently, `trimsuffix(..., "-")` can shorten it by one more, and the apply succeeds with a resource the operator did not name. The only guard is that today's longest legal combination happens to land on exactly 30.
## Relevant Logs and Errors
None — the absence of an error is the defect.
## Additional Context
* Suggested fix, in order of value: (1) replace the `substr` in both modules with a `precondition` (or a `validation` on the composed name) that fails with the offending value; (2) if truncation must stay for backward compatibility, log it via a `check` block; (3) correct `docs/naming-convention.md` to 7 so all five sources agree.
* Related: the `prefix` validations at `0-bootstrap/variables.tf:334` and `1-resman/variables.tf:287` disagree in form (`<= 7` vs `< 8`) though not in effect; `2-networking-*` and `3-security` both allow `< 10`, which is looser than either and would truncate.
Contributor guide
Research direction
Start with modules/project/main.tf:64 and modules/iam-service-account/main.tf:49, then review the existing prefix and tenant validations at the cited variables.tf locations. Reproduce the 30-character boundary with terraform plan and inspect the module tests or validation patterns available in the repository. Done means over-length IDs fail with a useful input-specific message and docs/naming-convention.md agrees with the seven-character limit.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- terraform
- Domain
- cloud, infrastructure
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100