Skip to content
Open
Show file tree
Hide file tree
Changes from 98 commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
3eb1b14
An initial draft of davinci codegen
henryrecker-pingidentity May 16, 2025
aeaa9ad
Updated fully-generated draft
henryrecker-pingidentity Jun 6, 2025
6d75ebe
Initial working resource, moving legacy sdk funcs to separate child p…
henryrecker-pingidentity Jun 9, 2025
99b8198
Fixes based on initial testing
henryrecker-pingidentity Jun 9, 2025
e662e89
Basic acceptance test
henryrecker-pingidentity Jun 9, 2025
2891e68
Move retry logic for new sdk into framework package
henryrecker-pingidentity Jun 10, 2025
0720ec4
Add tests for all variable types
henryrecker-pingidentity Jun 11, 2025
e895032
Handle secrets with separate sensitive attribute
henryrecker-pingidentity Jun 11, 2025
f157a31
Simplify error handling in new SDK
henryrecker-pingidentity Jun 11, 2025
e3089a6
Add resource-level validation
henryrecker-pingidentity Jun 11, 2025
005626b
Check for id presence in error handling
henryrecker-pingidentity Jun 11, 2025
79dc835
Use mux for a new provider with the new client
henryrecker-pingidentity Jun 12, 2025
65aa4db
Merge branch 'main' into DavinciVarInitialGenDraft
henryrecker-pingidentity Jun 12, 2025
3addb81
Move custom ValidateConfig to separate file
henryrecker-pingidentity Jun 17, 2025
e85bfcc
Reorder alphabetically
henryrecker-pingidentity Jun 17, 2025
bfc7636
Select region for acctest client
henryrecker-pingidentity Jun 17, 2025
a146439
Set user agent correctly
henryrecker-pingidentity Jun 17, 2025
451c613
WIP generated dv connector instance
henryrecker-pingidentity Jun 30, 2025
7009c41
Fix for unneeded error and diagnostics
henryrecker-pingidentity Jul 7, 2025
6c65324
Regenerated resource and tests
henryrecker-pingidentity Jul 8, 2025
ebbb1bd
WIP
henryrecker-pingidentity Jul 14, 2025
7ea3317
Handle non-UUID field
henryrecker-pingidentity Jul 23, 2025
2ef8fd8
Handle non-uuid id and get basic tests working
henryrecker-pingidentity Jul 23, 2025
6787d94
Add connector.id RequiresReplace, fix import regex, improve tests
henryrecker-pingidentity Jul 23, 2025
53b7e70
Custom error for DV-ignored properties
henryrecker-pingidentity Jul 23, 2025
63bb75e
Mark connector.id as required
henryrecker-pingidentity Jul 24, 2025
f33ecfc
Initial generated application resource with a successful create
henryrecker-pingidentity Jul 24, 2025
af5d041
Remove unneeded api_key_enabled attr
henryrecker-pingidentity Jul 25, 2025
28c640a
Generate correct computed+optional+required
henryrecker-pingidentity Jul 25, 2025
d6d9edd
Generate with enum and validator fixes
henryrecker-pingidentity Jul 28, 2025
7013c3f
Manual schema fixes
henryrecker-pingidentity Jul 28, 2025
e054ceb
Flesh out test HCL
henryrecker-pingidentity Jul 28, 2025
2a39c61
Build update request after create
henryrecker-pingidentity Jul 28, 2025
fe2ef4b
Fix wrong ID for post-create update
henryrecker-pingidentity Jul 28, 2025
530fab5
Davinci import regex
henryrecker-pingidentity Jul 28, 2025
f6aeadb
Schema defaults and set apiKeyEnabled in update
henryrecker-pingidentity Jul 28, 2025
a4edbe1
Test workarounds
henryrecker-pingidentity Jul 28, 2025
8118149
Fix properties read on imports
henryrecker-pingidentity Jul 28, 2025
cfb0b29
Fix attr name
henryrecker-pingidentity Jul 29, 2025
dbaa08d
Move handwritten code to separate file
henryrecker-pingidentity Jul 29, 2025
6670cfd
Add examples and generate docs
henryrecker-pingidentity Aug 7, 2025
3802255
Add more extensive tests
henryrecker-pingidentity Aug 7, 2025
38871e0
Regenerate doc
henryrecker-pingidentity Aug 7, 2025
59dddf6
Remove superfluous notes
henryrecker-pingidentity Aug 7, 2025
48f140c
Handle error in test region suffix build
henryrecker-pingidentity Aug 7, 2025
236f685
Add SG domain and fix user agent append
henryrecker-pingidentity Aug 7, 2025
a4c6782
Improve error output when no error ID present
henryrecker-pingidentity Aug 7, 2025
b037a9b
Add examples and docs and lint
henryrecker-pingidentity Aug 7, 2025
5a2d065
Initial complex properties test
henryrecker-pingidentity Aug 8, 2025
1a6c370
Passing complex tests, with secrets commented out
henryrecker-pingidentity Aug 8, 2025
ff796cf
Implement jsontypes.NormalizedObfuscatable
henryrecker-pingidentity Aug 8, 2025
8c20ed8
Use new json type in connector instance tests
henryrecker-pingidentity Aug 8, 2025
5d7410b
Mark properties as sensitive and format tests
henryrecker-pingidentity Aug 8, 2025
7409c77
Simplify test
henryrecker-pingidentity Aug 8, 2025
52a7f9c
Add test to cover optional properties and drift detection
henryrecker-pingidentity Aug 8, 2025
82a01c9
Cover modifying a sensitive attribute
henryrecker-pingidentity Aug 8, 2025
a3f4a25
Create davinci bootstrapped test env
henryrecker-pingidentity Aug 11, 2025
b2ef63e
Test bootstrapped and non bootstrapped DV env
henryrecker-pingidentity Aug 11, 2025
b4d09f7
Create davinci bootstrapped test env
henryrecker-pingidentity Aug 11, 2025
c45ef8e
Add tests covering bootstrapped DV env
henryrecker-pingidentity Aug 11, 2025
acd7171
Update to released client
henryrecker-pingidentity Aug 11, 2025
3bda7d1
Extend application tests, default all oauth sets to empty
henryrecker-pingidentity Aug 11, 2025
216179b
Create davinci bootstrapped test env
henryrecker-pingidentity Aug 11, 2025
c4f9092
Fill out tests for bootstrap and jwks
henryrecker-pingidentity Aug 11, 2025
a040cd6
Add examples and doc
henryrecker-pingidentity Aug 11, 2025
9c1d3f8
Add placeholder expand value to env read calls
henryrecker-pingidentity Aug 12, 2025
71da389
Changelog
henryrecker-pingidentity Aug 12, 2025
cccd787
Merge branch 'main' into DavinciVarInitialGenDraft
henryrecker-pingidentity Aug 12, 2025
01d2be7
Merge branch 'main' into DavinciVarInitialGenDraft
henryrecker-pingidentity Aug 12, 2025
23366ee
Fix mismatched provider schemas
henryrecker-pingidentity Aug 12, 2025
218a4a3
Add missing test util method for new SDK
henryrecker-pingidentity Aug 12, 2025
e0685c8
Avoid printing empty errors
henryrecker-pingidentity Aug 13, 2025
0e660f1
Update client version and remove placeholder expand values in tests
henryrecker-pingidentity Aug 13, 2025
ec21f58
Changelog update
henryrecker-pingidentity Aug 13, 2025
8f86338
Cleanup
henryrecker-pingidentity Aug 15, 2025
127fcbd
Schema cleanup
henryrecker-pingidentity Aug 15, 2025
107c9d3
Cleanup todos
henryrecker-pingidentity Aug 15, 2025
da32ce1
Cleanup schema
henryrecker-pingidentity Aug 15, 2025
93012ed
Lower-case region code when getting TLD
henryrecker-pingidentity Aug 20, 2025
54c9173
Move davinci env creation sweep to separate file
henryrecker-pingidentity Aug 20, 2025
8ff187a
Update client version
henryrecker-pingidentity Aug 20, 2025
198e3d8
Add retry wrapper for new sdk
henryrecker-pingidentity Aug 20, 2025
5e3ac55
Merge branch 'DavinciVarInitialGenDraft' into DavinciConnectorInstanc…
henryrecker-pingidentity Sep 4, 2025
15413c9
Merge branch 'DavinciConnectorInstanceResource' into DavinciApplicati…
henryrecker-pingidentity Sep 4, 2025
183b445
Fix forgotten conflict
henryrecker-pingidentity Sep 4, 2025
bc209df
Merge branch 'DavinciConnectorInstanceResource' into DavinciApplicati…
henryrecker-pingidentity Sep 4, 2025
2cef201
Merge branch 'main' into DavinciConnectorInstanceResource
henryrecker-pingidentity Sep 23, 2025
38da6d5
Marking connector instance as beta
henryrecker-pingidentity Sep 23, 2025
f9f5b07
Regenerate docs, removing beta resources
henryrecker-pingidentity Sep 23, 2025
b163e5f
Add note in beta.md with example test command
henryrecker-pingidentity Sep 23, 2025
a6ad025
Make command easier to copy
henryrecker-pingidentity Sep 23, 2025
74a4d60
Remove duplicate sweep env creation
henryrecker-pingidentity Sep 23, 2025
3149c94
Merge branch 'DavinciConnectorInstanceResource' into DavinciApplicati…
henryrecker-pingidentity Sep 23, 2025
c957fce
Mark davinci_application as beta
henryrecker-pingidentity Sep 23, 2025
3f2456a
Fix incorrect test precheck
henryrecker-pingidentity Sep 23, 2025
6dd1f76
Handle false value for enforce_signed_request_openid
Oct 3, 2025
c01a946
Merge branch 'main' into DavinciConnectorInstanceResource
henryrecker-pingidentity Dec 1, 2025
304a686
Merge branch 'DavinciConnectorInstanceResource' into DavinciApplicati…
henryrecker-pingidentity Dec 1, 2025
d9ae6ba
Merge branch 'main' into DavinciApplicationResource
henryrecker-pingidentity Dec 9, 2025
ae83d73
Add null and unknown check
henryrecker-pingidentity Dec 16, 2025
f3949d0
Fix duplicate resource declaration
henryrecker-pingidentity Dec 16, 2025
112cded
Replace example.com with pingidentity.com in tests
henryrecker-pingidentity Dec 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions betatemplates/resources/davinci_application.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}"
subcategory: "DaVinci"
description: |-
{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
---

# {{.Name}} ({{.Type}})

{{ .Description | trimspace }}

{{ if .HasExample -}}
## Example Usage

{{ tffile (printf "%s%s%s" "examples/resources/" .Name "/resource.tf") }}
{{- end }}

{{ .SchemaMarkdown | trimspace }}

{{ if .HasImport -}}
## Import

Import is supported using the following syntax, where attributes in `<>` brackets are replaced with the relevant ID. For example, `<environment_id>` should be replaced with the ID of the environment to import from.

{{ codefile "shell" (printf "%s%s%s" "examples/resources/" .Name "/import.sh") }}
{{- end }}
27 changes: 27 additions & 0 deletions betatemplates/resources/davinci_connector_instance.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
page_title: "{{.Name}} {{.Type}} - {{.RenderedProviderName}}"
subcategory: "DaVinci"
description: |-
{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
---

# {{.Name}} ({{.Type}})

{{ .Description | trimspace }}

{{ if .HasExample -}}
## Example Usage

{{ tffile (printf "%s%s%s" "examples/resources/" .Name "/resource.tf") }}
{{- end }}

{{ .SchemaMarkdown | trimspace }}

{{ if .HasImport -}}
## Import

Import is supported using the following syntax, where attributes in `<>` brackets are replaced with the relevant ID. For example, `<environment_id>` should be replaced with the ID of the environment to import from.

{{ codefile "shell" (printf "%s%s%s" "examples/resources/" .Name "/import.sh") }}
{{- end }}

8 changes: 8 additions & 0 deletions contributing/beta.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ Creating the GitHub release will automatically trigger a GitHub Action that runs

---

## Example Acceptance Test Command

To run acceptance tests for a beta resource, you will need to include both the `beta` build tag and set the environment variable `TESTACC_BETA=true`. For example, to run all tests for the beta resource `pingone_davinci_connector_instance` in the `davinci` service:

```
TF_ACC=1 TESTACC_BETA=true go test -tags=beta -v -timeout 300s -run ^TestAccDavinciConnectorInstance github.com/pingidentity/terraform-provider-pingone/internal/service/davinci
```

## VSCode Configuration Tip

To compile files with a `beta` tag in VSCode, you can instruct the Go language server (`gopls`) to always use the `beta` build tag.
Expand Down
1 change: 1 addition & 0 deletions examples/resources/pingone_davinci_application/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import pingone_davinci_application.example <environment_id>/<application_id>
44 changes: 44 additions & 0 deletions examples/resources/pingone_davinci_application/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
resource "pingone_davinci_application" "my_awesome_application" {
environment_id = var.pingone_environment_id

name = "My Awesome Application"

oauth = {
grant_types = ["authorizationCode"]
scopes = ["openid", "profile"]
enforce_signed_request_openid = false
redirect_uris = ["https://auth.pingone.com/0000-0000-000/rp/callback/openid_connect"]
}
}

resource "pingone_davinci_application_flow_policy" "authentication_flow_policy" {
environment_id = var.pingone_environment_id
application_id = pingone_davinci_application.my_awesome_application.id

name = "PingOne - Authentication"
status = "enabled"

flow_distributions = [
{
flow_id = pingone_davinci_flow.authentication.id
version = -1
weight = 100
}
]
}

resource "pingone_davinci_application_flow_policy" "registration_flow_policy" {
environment_id = var.pingone_environment_id
application_id = pingone_davinci_application.my_awesome_application.id

name = "PingOne - Registration"
status = "enabled"

flow_distributions = [
{
flow_id = pingone_davinci_flow.registration.id
version = -1
weight = 100
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import pingone_davinci_connector_instance.example <environment_id>/<instance_id>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
resource "pingone_davinci_connector_instance" "annotation_connector_example" {
environment_id = var.pingone_environment_id

connector = {
id = "annotationConnector"
}

name = "myAnnotationConnector"
}

resource "pingone_davinci_connector_instance" "crowdstrike_connector_example" {
environment_id = var.pingone_environment_id

connector = {
id = "crowdStrikeConnector"
}

name = "CrowdStrike"

properties = jsonencode({
"clientId" : var.crowdstrike_client_id,
"clientSecret" : var.crowdstrike_client_secret
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright © 2025 Ping Identity Corporation

package jsontypes

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)

// Ensure the implementation satisfies the expected interfaces
var _ basetypes.StringTypable = NormalizedObfuscatableType{}

// NormalizedObfuscatableType is a custom type for handling JSON strings that might contain
// obfuscated fields (represented as a string with non-zero length made up of only asterisks).
// It allows for semantic equality checking that ignores these obfuscated fields.
type NormalizedObfuscatableType struct {
basetypes.StringType
}

func (t NormalizedObfuscatableType) Equal(o attr.Type) bool {
other, ok := o.(NormalizedObfuscatableType)

if !ok {
return false
}

return t.StringType.Equal(other.StringType)
}

func (t NormalizedObfuscatableType) String() string {
return "jsontypes.NormalizedObfuscatableType"
}

func (t NormalizedObfuscatableType) ValueFromString(ctx context.Context, in basetypes.StringValue) (basetypes.StringValuable, diag.Diagnostics) {
// NormalizedObfuscatableValue defined in the value type file
value := NormalizedObfuscatableValue{
StringValue: in,
}

return value, nil
}

func (t NormalizedObfuscatableType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
attrValue, err := t.StringType.ValueFromTerraform(ctx, in)

if err != nil {
return nil, err
}

stringValue, ok := attrValue.(basetypes.StringValue)

if !ok {
return nil, fmt.Errorf("unexpected value type of %T", attrValue)
}

stringValuable, diags := t.ValueFromString(ctx, stringValue)

if diags.HasError() {
return nil, fmt.Errorf("unexpected error converting StringValue to StringValuable: %v", diags)
}

return stringValuable, nil
}

func (t NormalizedObfuscatableType) ValueType(ctx context.Context) attr.Value {
// NormalizedObfuscatableValue defined in the value type file
return NormalizedObfuscatableValue{}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Copyright © 2025 Ping Identity Corporation

package jsontypes

import (
"context"
"encoding/json"
"fmt"

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/attr/xattr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
)

// Ensure the implementation satisfies the expected interfaces
var _ basetypes.StringValuable = NormalizedObfuscatableValue{}
var _ basetypes.StringValuableWithSemanticEquals = NormalizedObfuscatableValue{}
var _ xattr.ValidateableAttribute = NormalizedObfuscatableValue{}

// Alias useful in schemas and structs
type NormalizedObfuscatable = NormalizedObfuscatableValue

// NormalizedObfuscatableValue is a custom value for handling JSON strings that might contain
// obfuscated fields (represented as a string with non-zero length made up of only asterisks).
// It allows for semantic equality checking that ignores these obfuscated fields.
type NormalizedObfuscatableValue struct {
basetypes.StringValue
}

func (v NormalizedObfuscatableValue) Equal(o attr.Value) bool {
other, ok := o.(NormalizedObfuscatableValue)

if !ok {
return false
}

return v.StringValue.Equal(other.StringValue)
}

func (v NormalizedObfuscatableValue) Type(ctx context.Context) attr.Type {
return NormalizedObfuscatableType{}
}

func (v NormalizedObfuscatableValue) StringSemanticEquals(ctx context.Context, newValuable basetypes.StringValuable) (bool, diag.Diagnostics) {
var diags diag.Diagnostics

// The framework should always pass the correct value type, but always check
newValue, ok := newValuable.(NormalizedObfuscatableValue)

if !ok {
diags.AddError(
"JSON String Type Semantic Equality Check Error",
"An unexpected value type was received while performing semantic equality checks. "+
"Please report this to the provider developers.\n\n"+
"Expected Value Type: "+fmt.Sprintf("%T", v)+"\n"+
"Got Value Type: "+fmt.Sprintf("%T", newValuable),
)

return false, diags
}

return semanticCompareJsonIgnoreObfuscated(v.StringValue.ValueString(), newValue.StringValue.ValueString()), diags
}

// Semantically compare the json blobs, ignoring fields that are strings of asterisks, which may have been obfuscated
func semanticCompareJsonIgnoreObfuscated(json1, json2 string) bool {
var marshalled1, marshalled2 map[string]interface{}

// Unmarshal both JSON blobs into generic maps. Return false if parsing fails.
if err := json.Unmarshal([]byte(json1), &marshalled1); err != nil {
return false
}
if err := json.Unmarshal([]byte(json2), &marshalled2); err != nil {
return false
}

ignoreRedactedFields := cmp.FilterPath(func(p cmp.Path) bool {
// Get the values being compared at the current path
vx, vy := p.Last().Values()

if !vx.IsValid() || !vy.IsValid() {
return false
}

vxStr, okX := vx.Interface().(string)
vyStr, okY := vy.Interface().(string)

// If the values are strings, and one or both are strings of asterisks, we ignore this path
if okX && okY {
return isAllAsterisks(vxStr) || isAllAsterisks(vyStr)
}
return false
}, cmp.Ignore())

return cmp.Equal(marshalled1, marshalled2, ignoreRedactedFields)
}

func isAllAsterisks(s string) bool {
if len(s) == 0 {
return false
}
for _, char := range s {
if char != '*' {
return false
}
}
return true
}

func NormalizedObfuscatableNull() NormalizedObfuscatableValue {
return NormalizedObfuscatableValue{
StringValue: basetypes.NewStringNull(),
}
}

func NormalizedObfuscatableUnknown() NormalizedObfuscatableValue {
return NormalizedObfuscatableValue{
StringValue: basetypes.NewStringUnknown(),
}
}

func NormalizedObfuscatableStringValue(value string) NormalizedObfuscatableValue {
return NormalizedObfuscatableValue{
StringValue: basetypes.NewStringValue(value),
}
}

func NormalizedObfuscatableStringPointerValue(value *string) NormalizedObfuscatableValue {
return NormalizedObfuscatableValue{
StringValue: basetypes.NewStringPointerValue(value),
}
}

func (v NormalizedObfuscatableValue) ValidateAttribute(ctx context.Context, req xattr.ValidateAttributeRequest, resp *xattr.ValidateAttributeResponse) {
if v.IsNull() || v.IsUnknown() {
return
}

// Validate that the string is valid JSON
var jsonData interface{}
if err := json.Unmarshal([]byte(v.ValueString()), &jsonData); err != nil {
resp.Diagnostics.AddAttributeError(
req.Path,
"JSON String Type Validation Error",
fmt.Sprintf("The value could not be unmarshalled as JSON: %s", err.Error()),
)
}
}
3 changes: 3 additions & 0 deletions internal/framework/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,9 @@ func ParseImportID(id string, components ...ImportComponent) (map[string]string,

i := 0
for _, v := range components {
if v.Regexp == nil {
return nil, fmt.Errorf("cannot parse import ID as component %d has no Regexp", i)
}
keys[i] = v.Label
regexpList[i] = v.Regexp.String()
i++
Expand Down
Loading