Skip to content

resource/pingone_davinci_flow: form node theme reference (theme.value / themeId.value) not resolved as embedded reference - #129

Merged
samir-gandhi merged 2 commits into
mainfrom
polaris/issue-128-form-node-theme-reference
Jul 21, 2026
Merged

resource/pingone_davinci_flow: form node theme reference (theme.value / themeId.value) not resolved as embedded reference#129
samir-gandhi merged 2 commits into
mainfrom
polaris/issue-128-form-node-theme-reference

Conversation

@samir-gandhi

Copy link
Copy Markdown
Contributor

What Was Built

Resolve pingone_davinci_flow form-node theme/UI-template references (theme.value and themeId.value) as embedded Terraform references or fallback variables, closing #128.

pingOneFormsConnector showForm nodes can embed a theme/UI-template reference in three shapes — a direct UUID at theme.value, an absent theme key, or an indirect mode flag (theme.value == "useThemeId") pointing at a rich-text/Slate-wrapped UUID in a sibling themeId.value field. None of these were resolved before this change; they were emitted as inert raw strings in the exported HCL. This mirrors the treatment already given to form.value, which resolves via the existing EmbeddedReferenceRule mechanism.

This change extends that generic mechanism with two new optional, zero-value-safe fields (PreconditionKeyPath/PreconditionValue for cross-key gating, UnwrapMode for the rich-text/Slate wrapper) plus an unconditional UUID-format validation guard, then registers two new declarative rules against pingone_branding_theme (currently unexported, so both rules fall back to a Terraform variable until that resource is added, matching the form.value/pingone_davinci_form precedent).

Key Decisions

  • Target resource type: pingone_branding_theme, confirmed real and not-yet-exported (contributing/RESOURCE_COVERAGE.md), with Strategy: "reference_with_fallback" — same bootstrapping pattern used for form.value before pingone_davinci_form existed.
  • UUID-format guard, not a sentinel denylist: the initial design added a SkipValues []string list ("useThemeId", "activeTheme") to stop the fallback strategy from corrupting the mode-flag sentinel. Replaced with a general, self-maintaining fix: an unconditional UUID-format guard (via github.com/google/uuid, already a direct dependency) applied to every extraction, regardless of strategy. Any non-UUID-shaped string is left untouched — no enumeration required, and any future sentinel DaVinci might add is automatically covered.
  • Rich-text rewrap requires escaping-aware logic: the Slate wrapper is JSON-encoded a second time when the outer properties map is marshaled, so quotes inside it are backslash-escaped in the raw HCL text. A new sibling helper (replaceRichTextInRawHCL) re-derives escaping via json.Marshal rather than reusing the existing plain substring-replace helper.
  • Only the literal sentinel "useThemeId" gates case 3; "activeTheme" is left alone — not via a special case, but because it fails the general UUID-format guard like any other non-UUID string.
  • mfaPolicyId/userId (same rich-text wrapper shape elsewhere in showForm's properties) are explicitly out of scope for this change.

Changes

  • internal/core/embedded_references.go — new PreconditionKeyPath/PreconditionValue/UnwrapMode fields on EmbeddedReferenceRule, unconditional looksLikeUUID guard, unwrapRichText/replaceRichTextInRawHCL helpers.
  • internal/core/embedded_references_test.go — corrected ~10 existing non-UUID-shaped fixtures to valid UUIDs (needed by the new guard); added tests for precondition, rich-text unwrap, malformed wrappers, and the guard across all strategies.
  • internal/platform/pingone/resource_flow.go — two new rule registrations targeting pingone_branding_theme.
  • internal/platform/pingone/resource_flow_test.go, dispatch_test.go — behavioral and registration-presence tests.
  • contributing/ARCHITECTURE.md, contributing/DEVELOPER_HANDBOOK.md — documented the new fields and guard.
  • .changelog/pr-128.txt — enhancement changelog entry.

Test plan

  • Case 1, UUID not in graph → variable fallback — Verified by Polaris QA
  • Case 1, UUID in graph → resource reference + graph edge, no fallback — Verified by Polaris QA
  • Case 2, theme absent → byte-for-byte unchanged — Verified by Polaris QA
  • Case 3, UUID not in graph, wrapper preserved, theme.value untouched — Verified by Polaris QA
  • Case 3, UUID in graph → reference inside wrapper + graph edge, theme.value untouched — Verified by Polaris QA
  • theme.value == "activeTheme" sentinel, no themeId, unchanged — Verified by Polaris QA
  • form.value resolves independently of theme case — Verified by Polaris QA
  • customForm nodes unaffected, no capability-aware branching — Verified by Polaris QA
  • Existing subFlowId/form.value tests pass unchanged with zero-value new fields — Verified by Polaris QA
  • New tests cover precondition, rich-text unwrap (both outcomes), malformed wrapper, and the UUID-format guard across all strategies — Verified by Polaris QA
  • pingone_branding_theme need not exist as an exported resource for this change to be complete — Verified by Polaris QA

🤖 Generated with Claude Code

samir-gandhi and others added 2 commits July 21, 2026 14:14
…p, and UUID-format guard

Adds PreconditionKeyPath/PreconditionValue (gate a rule on a sibling JSON
key's value) and UnwrapMode "rich_text" (extract/re-embed a UUID nested
inside a Slate-style rich-text wrapper) to EmbeddedReferenceRule, plus an
unconditional looksLikeUUID guard (backed by github.com/google/uuid) applied
before any Strategy branch runs. This replaces a hardcoded sentinel denylist
approach with a general check: only UUID-shaped strings are ever resolved as
references/fallback variables, so future DaVinci sentinel values (beyond
"useThemeId"/"activeTheme") are rejected without further code changes.

Both new fields are zero-value-safe — existing subFlowId/form.value rules
are unaffected. Corrects non-UUID-shaped placeholder fixtures in
embedded_references_test.go that are asserted to resolve, and adds tests for
precondition match/no-match/absent-key, rich-text unwrap resolving to both a
variable and a graph reference, malformed wrapper shapes, and the
UUID-format guard's no-op behavior across all three Strategy values.

Lays groundwork for registering pingone_branding_theme rules against
theme.value/themeId.value on DaVinci showForm nodes in a follow-up change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ed reference rules for theme.value and themeId.value

Adds two EmbeddedReferenceRule registrations mirroring the existing
form.value rule: theme.value (case 1, direct UUID) and themeId.value
(case 3, rich-text-wrapped UUID gated on theme.value == "useThemeId").
Both target pingone_branding_theme with reference_with_fallback so the
UUID resolves to a graph reference when available, otherwise a
Terraform variable — matching the form.value/pingone_davinci_form
bootstrap precedent. The unconfirmed "activeTheme" sentinel and the
theme-absent case require no special-casing: they're rejected by Task
1's unconditional UUID-format guard.

Adds a registration-presence test in dispatch_test.go and end-to-end
behavioral tests in resource_flow_test.go covering all six plan
acceptance criteria (fallback/reference resolution for both cases,
theme-absent unchanged, activeTheme-without-themeId unchanged,
form.value independence, customForm unaffected).
@github-actions

Copy link
Copy Markdown

Regression Test Results

Matrix Entry Status Breaking Acceptable
default-hcl ✅ PASS 0 0
default-tfjson ✅ PASS 0 0
hcl-include-all ✅ PASS 0 0
hcl-skip-deps ✅ PASS 0 0

✅ No regressions detected

All export configurations produced compatible output.


Generated by regression workflow • View run

@github-actions

Copy link
Copy Markdown

Regression Test Results

Matrix Entry Status Breaking Acceptable
default-hcl ✅ PASS 0 0
default-tfjson ✅ PASS 0 0
hcl-include-all ✅ PASS 0 0
hcl-skip-deps ✅ PASS 0 0
tfjson-skip-deps ✅ PASS 0 0

✅ No regressions detected

All export configurations produced compatible output.


Generated by regression workflow • View run

@samir-gandhi
samir-gandhi merged commit 92cda54 into main Jul 21, 2026
15 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant