Skip to content

[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) #228

Description

@JohnHales

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,
<prefix>-<env>-<tenant>-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
-<env>- envs_folders keys, longest shipped is Test 6
<tenant> 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 fix(0-bootstrap): declare billing_override, fix the assured_workload output, align the prefix limit #213 (1ce9c3f3, merged 2026-09-05).
  • Deployment Type:
    • US Region Restricted (e.g., Access Policy constraint)
    • FedRAMP Moderate
    • FedRAMP High
    • DoD IL4
    • DoD IL5
    • Stand-alone / Custom
  • FAST Stage (if applicable): shared modules, reached from every stage; the zero-margin case is Stage 1
    • Stage 0 (Bootstrap)
    • 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Level of Effort - LowQuick, well-defined tasks with no unknowns; takes a few hours up to one day to completePriority - LowMinor polish, typo fixes, or technical debt; nice to have; pick up when time permitsbugSomething isn't working

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions