Skip to content

Reference fallback-variable name collides across resources referencing different instances of the same not-yet-exported type #138

Description

@samir-gandhi

Description

internal/core/orchestrator.go's reference-fallback path derives a Terraform variable name purely from the static schema declaration (references_type + reference_field), never from the actual UUID or the referencing resource's identity:

// resolveOneReference — fallback when the target resource type has no graph node
varName := attrDef.ReferencesType
if attrDef.ReferenceField != "" {
    varName = attrDef.ReferencesType + "_" + attrDef.ReferenceField
}
return ResolvedReference{
    IsVariable:   true,
    VariableName: varName,
    OriginalValue: uuid,
}

collectFallbackVars then dedupes FallbackVariable entries on this same static VariableName:

if !seen[ref.VariableName] {
    seen[ref.VariableName] = true
    *out = append(*out, FallbackVariable{
        Name:    ref.VariableName,
        Default: ref.OriginalValue,
        ...
    })
}

Net effect: every resource of a given type that references a not-yet-exported target type (e.g. pingone_branding_theme, pingone_password_policy) collapses onto the same variable name regardless of which actual instance (UUID) it points to. The first resource's UUID wins as the Default value in .tfvars; every other resource with a different target UUID silently gets rewritten to reference the same variable — pointing it at the wrong resource with no error, warning, or test failure.

Unlike #130 (which requires a specific name-derivation collision, e.g. two DaVinci flow nodes sharing a human-readable title), this path collides unconditionally — it only takes two resources of the same type referencing two different instances of the same missing dependency type, which is a common, not edge-case, scenario.

Evidence

Reproduced live against a real PingOne environment via the exporter's pingone_population support (added in #135, part of the pilot fleet in #119):

$ curl .../populations | jq
Sample Users      | theme.id = ca2d934c-5c98-42e0-8c09-fcbc559049b0
More Sample Users | theme.id = ca2d934c-5c98-42e0-8c09-fcbc559049b0
sam-population     | theme.id = df05370a-07f3-4ed0-927a-9cc307ed8780   # <-- different theme

Exported HCL (pingone_population.tf):

resource "pingone_population" "pingcli__sam-population" {
  ...
  theme = { id = var.pingone_branding_theme_id }   # same variable as the other two
}

.tfvars only has one entry: pingone_branding_theme_id = "ca2d934c-..."sam-population's theme is silently wrong; applying this config would set the wrong branding theme on that population.

password_policy on sam-population is not affected by the collision today only because it's the sole population with a non-nil password_policy in this dataset — but the underlying dedup key (pingone_password_policy_id, with no UUID/resource discriminator) has the exact same defect and would collide the moment a second population sets a different password policy.

Expected Behavior

Two distinct UUIDs referencing the same not-yet-exported target type must never collapse into the same fallback variable. Likely fix directions (not prescriptive — worth scoping separately from #130's fix, since the fix location/mechanism differs even though the failure mode is the same class of bug):

Affected Code

  • internal/core/orchestrator.goresolveOneReference (variable name derivation, no UUID awareness), collectFallbackVars (dedup keyed on name, not UUID)
  • Any resource definition with a references_type pointing at a not-yet-exported resource type is exposed — currently pingone_population (theme, password_policy), pingone_application (key_rotation_policy_id, per resource/pingone_application: add export support #137), and will affect essentially every future resource added from the PingOne Provider Coverage Tracker #119 backlog until fixed, since most reference at least one not-yet-exported type during incremental rollout.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions