• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Twingate / terraform-provider-twingate / 15570780021

10 Jun 2025 09:33PM UTC coverage: 85.477% (-0.1%) from 85.582%
15570780021

Pull #732

github

web-flow
Bump github.com/cloudflare/circl from 1.6.0 to 1.6.1

Bumps [github.com/cloudflare/circl](https://github.com/cloudflare/circl) from 1.6.0 to 1.6.1.
- [Release notes](https://github.com/cloudflare/circl/releases)
- [Commits](https://github.com/cloudflare/circl/compare/v1.6.0...v1.6.1)

---
updated-dependencies:
- dependency-name: github.com/cloudflare/circl
  dependency-version: 1.6.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #732: Bump github.com/cloudflare/circl from 1.6.0 to 1.6.1

8193 of 9585 relevant lines covered (85.48%)

2.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.83
/twingate/internal/test/acctests/helper.go
1
package acctests
2

3
import (
4
        "context"
5
        "errors"
6
        "fmt"
7
        "log"
8
        "os"
9
        "strings"
10
        "testing"
11
        "time"
12

13
        "github.com/Twingate/terraform-provider-twingate/v3/twingate"
14
        "github.com/Twingate/terraform-provider-twingate/v3/twingate/internal/attr"
15
        "github.com/Twingate/terraform-provider-twingate/v3/twingate/internal/client"
16
        "github.com/Twingate/terraform-provider-twingate/v3/twingate/internal/model"
17
        "github.com/Twingate/terraform-provider-twingate/v3/twingate/internal/provider/datasource"
18
        "github.com/Twingate/terraform-provider-twingate/v3/twingate/internal/provider/resource"
19
        "github.com/Twingate/terraform-provider-twingate/v3/twingate/internal/test"
20
        "github.com/hashicorp/terraform-plugin-framework/providerserver"
21
        "github.com/hashicorp/terraform-plugin-go/tfprotov6"
22
        sdk "github.com/hashicorp/terraform-plugin-testing/helper/resource"
23
        "github.com/hashicorp/terraform-plugin-testing/plancheck"
24
        "github.com/hashicorp/terraform-plugin-testing/terraform"
25
        "github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
26
)
27

28
var (
29
        ErrResourceIDNotSet            = errors.New("id not set")
30
        ErrResourceNotFound            = errors.New("resource not found")
31
        ErrResourceStillPresent        = errors.New("resource still present")
32
        ErrResourceFoundInState        = errors.New("this resource should not be here")
33
        ErrUnknownResourceType         = errors.New("unknown resource type")
34
        ErrClientNotInitialized        = errors.New("meta client not initialized")
35
        ErrSecurityPoliciesNotFound    = errors.New("security policies not found")
36
        ErrInvalidPath                 = errors.New("invalid path: the path value cannot be asserted as string")
37
        ErrNotNullSecurityPolicy       = errors.New("expected null security policy in GroupAccess, got non null")
38
        ErrNotNullUsageBased           = errors.New("expected null usage based duration in GroupAccess, got non null")
39
        ErrNullSecurityPolicy          = errors.New("expected non null security policy in GroupAccess, got null")
40
        ErrNullUsageBased              = errors.New("expected non null usage based duration in GroupAccess, got null")
41
        ErrEmptyGroupAccess            = errors.New("expected at least one group in GroupAccess")
42
        ErrNotNullUsageBasedOnResource = errors.New("expected null usage based duration on Resource, got non null")
43
        ErrEmptyTagsList               = errors.New("expected non-empty list of tags")
44
)
45

46
func ErrServiceAccountsLenMismatch(expected, actual int) error {
×
47
        return fmt.Errorf("expected %d service accounts, actual - %d", expected, actual) //nolint
×
48
}
×
49

50
func ErrDNSProfileAllowedDomainsLenMismatch(expected, actual int) error {
×
51
        return fmt.Errorf("expected %d allowed domains, actual - %d", expected, actual) //nolint
×
52
}
×
53

54
func ErrGroupsLenMismatch(expected, actual int) error {
×
55
        return fmt.Errorf("expected %d groups, actual - %d", expected, actual) //nolint
×
56
}
×
57

58
func ErrUsersLenMismatch(expected, actual int) error {
×
59
        return fmt.Errorf("expected %d users, actual - %d", expected, actual) //nolint
×
60
}
×
61

62
var providerClient = func() *client.Client { //nolint
3✔
63
        client, err := test.TwingateClient()
3✔
64
        if err != nil {
3✔
65
                log.Fatal("failed to init client:", err)
×
66
        }
×
67

68
        return client
3✔
69
}()
70

71
var ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){ //nolint
72
        "twingate": providerserver.NewProtocol6WithError(twingate.New(client.DefaultAgent, "test")()),
73
}
74

75
const WaitDuration = 500 * time.Millisecond
76

77
func WaitTestFunc() sdk.TestCheckFunc {
3✔
78
        return func(state *terraform.State) error {
6✔
79
                // Sleep 500 ms
3✔
80
                time.Sleep(WaitDuration)
3✔
81

3✔
82
                return nil
3✔
83
        }
3✔
84
}
85

86
func ComposeTestCheckFunc(checkFuncs ...sdk.TestCheckFunc) sdk.TestCheckFunc {
3✔
87
        return func(state *terraform.State) error {
6✔
88
                if err := WaitTestFunc()(state); err != nil {
3✔
89
                        return fmt.Errorf("WaitTestFunc error: %w", err)
×
90
                }
×
91

92
                for i, f := range checkFuncs {
6✔
93
                        if err := f(state); err != nil {
6✔
94
                                return fmt.Errorf("check %d/%d error: %w", i+1, len(checkFuncs), err)
3✔
95
                        }
3✔
96
                }
97

98
                return nil
3✔
99
        }
100
}
101

102
func PreCheck(t *testing.T) {
2✔
103
        t.Helper()
2✔
104

2✔
105
        var requiredEnvironmentVariables = []string{
2✔
106
                twingate.EnvAPIToken,
2✔
107
                twingate.EnvNetwork,
2✔
108
                twingate.EnvURL,
2✔
109
        }
2✔
110

2✔
111
        t.Run("Test Twingate Resource : AccPreCheck", func(t *testing.T) {
4✔
112
                for _, requiredEnvironmentVariable := range requiredEnvironmentVariables {
4✔
113
                        if value := os.Getenv(requiredEnvironmentVariable); value == "" {
2✔
114
                                t.Fatalf("%s must be set before running acceptance tests.", requiredEnvironmentVariable)
×
115
                        }
×
116
                }
117
        })
118
}
119

120
func CheckTwingateResourceDoesNotExists(resourceName string) sdk.TestCheckFunc {
×
121
        return func(s *terraform.State) error {
×
122
                _, ok := s.RootModule().Resources[resourceName]
×
123
                if !ok {
×
124
                        return nil
×
125
                }
×
126

127
                return fmt.Errorf("%w: %s", ErrResourceFoundInState, resourceName)
×
128
        }
129
}
130

131
func CheckTwingateServiceAccountDestroy(s *terraform.State) error {
2✔
132
        for _, rs := range s.RootModule().Resources {
4✔
133
                if rs.Type != resource.TwingateServiceAccount {
4✔
134
                        continue
2✔
135
                }
136

137
                serviceAccountID := rs.Primary.ID
2✔
138

2✔
139
                serviceAccount, _ := providerClient.ReadShallowServiceAccount(context.Background(), serviceAccountID)
2✔
140
                if serviceAccount != nil {
2✔
141
                        return fmt.Errorf("%w with ID %s", ErrResourceStillPresent, serviceAccountID)
×
142
                }
×
143
        }
144

145
        return nil
2✔
146
}
147

148
func CheckTwingateResourceExists(resourceName string) sdk.TestCheckFunc {
3✔
149
        return func(s *terraform.State) error {
5✔
150
                resource, ok := s.RootModule().Resources[resourceName]
2✔
151

2✔
152
                if !ok {
2✔
153
                        return fmt.Errorf("%w: %s", ErrResourceNotFound, resourceName)
×
154
                }
×
155

156
                if resource.Primary.ID == "" {
2✔
157
                        return ErrResourceIDNotSet
×
158
                }
×
159

160
                return nil
2✔
161
        }
162
}
163

164
func GetTwingateResourceID(resourceName string, resourceID **string) sdk.TestCheckFunc {
3✔
165
        return func(s *terraform.State) error {
5✔
166
                resource, ok := s.RootModule().Resources[resourceName]
2✔
167

2✔
168
                if !ok {
2✔
169
                        return fmt.Errorf("%w: %s", ErrResourceNotFound, resourceName)
×
170
                }
×
171

172
                if resource.Primary.ID == "" {
2✔
173
                        return ErrResourceIDNotSet
×
174
                }
×
175

176
                id := resource.Primary.ID
2✔
177
                *resourceID = &id
2✔
178

2✔
179
                return nil
2✔
180
        }
181
}
182

183
func DatasourceName(resource, name string) string {
3✔
184
        return fmt.Sprintf("data.%s.%s", resource, name)
3✔
185
}
3✔
186

187
func ResourceName(resource, name string) string {
3✔
188
        return fmt.Sprintf("%s.%s", resource, name)
3✔
189
}
3✔
190

191
func TerraformResource(name string) string {
3✔
192
        return ResourceName(resource.TwingateResource, name)
3✔
193
}
3✔
194

195
func TerraformRemoteNetwork(name string) string {
3✔
196
        return ResourceName(resource.TwingateRemoteNetwork, name)
3✔
197
}
3✔
198

199
func TerraformGroup(name string) string {
3✔
200
        return ResourceName(resource.TwingateGroup, name)
3✔
201
}
3✔
202

203
func TerraformConnector(name string) string {
3✔
204
        return ResourceName(resource.TwingateConnector, name)
3✔
205
}
3✔
206

207
func TerraformConnectorTokens(name string) string {
3✔
208
        return ResourceName(resource.TwingateConnectorTokens, name)
3✔
209
}
3✔
210

211
func TerraformServiceAccount(name string) string {
3✔
212
        return ResourceName(resource.TwingateServiceAccount, name)
3✔
213
}
3✔
214

215
func TerraformServiceKey(name string) string {
3✔
216
        return ResourceName(resource.TwingateServiceAccountKey, name)
3✔
217
}
3✔
218

219
func TerraformUser(name string) string {
3✔
220
        return ResourceName(resource.TwingateUser, name)
3✔
221
}
3✔
222

223
func TerraformDNSFilteringProfile(name string) string {
3✔
224
        return ResourceName(resource.TwingateDNSFilteringProfile, name)
3✔
225
}
3✔
226

227
func TerraformDatasourceUsers(name string) string {
3✔
228
        return DatasourceName(datasource.TwingateUsers, name)
3✔
229
}
3✔
230

231
func DeleteTwingateResource(resourceName, resourceType string) sdk.TestCheckFunc {
3✔
232
        return func(s *terraform.State) error {
5✔
233
                resourceState, ok := s.RootModule().Resources[resourceName]
2✔
234
                if !ok {
2✔
235
                        return fmt.Errorf("%w: %s ", ErrResourceNotFound, resourceName)
×
236
                }
×
237

238
                resourceID := resourceState.Primary.ID
2✔
239
                if resourceID == "" {
2✔
240
                        return ErrResourceIDNotSet
×
241
                }
×
242

243
                err := deleteResource(resourceType, resourceID)
2✔
244
                if err != nil {
2✔
245
                        return fmt.Errorf("%s with ID %s still active: %w", resourceType, resourceID, err)
×
246
                }
×
247

248
                return nil
2✔
249
        }
250
}
251

252
func deleteResource(resourceType, resourceID string) error {
2✔
253
        var err error
2✔
254

2✔
255
        switch resourceType {
2✔
256
        case resource.TwingateResource:
2✔
257
                err = providerClient.DeleteResource(context.Background(), resourceID)
2✔
258
        case resource.TwingateRemoteNetwork:
2✔
259
                err = providerClient.DeleteRemoteNetwork(context.Background(), resourceID)
2✔
260
        case resource.TwingateGroup:
2✔
261
                err = providerClient.DeleteGroup(context.Background(), resourceID)
2✔
262
        case resource.TwingateConnector:
2✔
263
                err = providerClient.DeleteConnector(context.Background(), resourceID)
2✔
264
        case resource.TwingateServiceAccount:
2✔
265
                err = providerClient.DeleteServiceAccount(context.Background(), resourceID)
2✔
266
        case resource.TwingateServiceAccountKey:
2✔
267
                err = providerClient.DeleteServiceKey(context.Background(), resourceID)
2✔
268
        case resource.TwingateUser:
2✔
269
                err = providerClient.DeleteUser(context.Background(), resourceID)
2✔
270
        default:
×
271
                err = fmt.Errorf("%s %w", resourceType, ErrUnknownResourceType)
×
272
        }
273

274
        return err
2✔
275
}
276

277
func CheckTwingateResourceDestroy(s *terraform.State) error {
2✔
278
        for _, rs := range s.RootModule().Resources {
4✔
279
                if rs.Type != resource.TwingateResource {
4✔
280
                        continue
2✔
281
                }
282

283
                resourceID := rs.Primary.ID
2✔
284

2✔
285
                resource, _ := providerClient.ReadResource(context.Background(), resourceID)
2✔
286
                if resource != nil {
2✔
287
                        return fmt.Errorf("%w: with ID %s", ErrResourceStillPresent, resourceID)
×
288
                }
×
289
        }
290

291
        return nil
2✔
292
}
293

294
func DeactivateTwingateResource(resourceName string) sdk.TestCheckFunc {
3✔
295
        return func(s *terraform.State) error {
5✔
296
                resourceState, ok := s.RootModule().Resources[resourceName]
2✔
297

2✔
298
                if !ok {
2✔
299
                        return fmt.Errorf("%w: %s", ErrResourceNotFound, resourceName)
×
300
                }
×
301

302
                resourceID := resourceState.Primary.ID
2✔
303

2✔
304
                if resourceID == "" {
2✔
305
                        return ErrResourceIDNotSet
×
306
                }
×
307

308
                err := providerClient.UpdateResourceActiveState(context.Background(), &model.Resource{
2✔
309
                        ID:       resourceID,
2✔
310
                        IsActive: false,
2✔
311
                })
2✔
312

2✔
313
                if err != nil {
2✔
314
                        return fmt.Errorf("resource with ID %s still active: %w", resourceID, err)
×
315
                }
×
316

317
                return nil
2✔
318
        }
319
}
320

321
func CheckTwingateResource(resourceName string, check func(res *model.Resource) error) sdk.TestCheckFunc {
3✔
322
        return func(s *terraform.State) error {
5✔
323
                resourceState, ok := s.RootModule().Resources[resourceName]
2✔
324

2✔
325
                if !ok {
2✔
326
                        return fmt.Errorf("%w: %s", ErrResourceNotFound, resourceName)
×
327
                }
×
328

329
                if resourceState.Primary.ID == "" {
2✔
330
                        return ErrResourceIDNotSet
×
331
                }
×
332

333
                res, err := providerClient.ReadResource(context.Background(), resourceState.Primary.ID)
2✔
334
                if err != nil {
2✔
335
                        return fmt.Errorf("failed to read resource: %w", err)
×
336
                }
×
337

338
                return check(res)
2✔
339
        }
340
}
341

342
func CheckTwingateResourceSecurityPolicyOnGroupAccess(resourceName string, expectedSecurityPolicy string) sdk.TestCheckFunc {
2✔
343
        return CheckTwingateResource(resourceName, func(res *model.Resource) error {
4✔
344
                if len(res.GroupsAccess) == 0 {
2✔
345
                        return ErrEmptyGroupAccess
×
346
                }
×
347

348
                if res.GroupsAccess[0].SecurityPolicyID == nil {
2✔
349
                        return ErrNullSecurityPolicy
×
350
                }
×
351

352
                if *res.GroupsAccess[0].SecurityPolicyID != expectedSecurityPolicy {
2✔
353
                        return fmt.Errorf("expected security policy %v, got %v", expectedSecurityPolicy, *res.GroupsAccess[0].SecurityPolicyID) //nolint:err113
×
354
                }
×
355

356
                return nil
2✔
357
        })
358
}
359

360
func CheckTwingateResourceUsageBasedOnGroupAccess(resourceName string, expectedUsageBased int64) sdk.TestCheckFunc {
3✔
361
        return CheckTwingateResource(resourceName, func(res *model.Resource) error {
5✔
362
                if len(res.GroupsAccess) == 0 {
2✔
363
                        return ErrEmptyGroupAccess
×
364
                }
×
365

366
                if res.GroupsAccess[0].UsageBasedDuration == nil {
2✔
367
                        return ErrNullUsageBased
×
368
                }
×
369

370
                if *res.GroupsAccess[0].UsageBasedDuration != expectedUsageBased {
2✔
371
                        return fmt.Errorf("expected usage based duration %v, got %v", expectedUsageBased, *res.GroupsAccess[0].UsageBasedDuration) //nolint:err113
×
372
                }
×
373

374
                return nil
2✔
375
        })
376
}
377

378
func CheckTwingateResourceUsageBasedDuration(resourceName string, expectedUsageBased int64) sdk.TestCheckFunc {
3✔
379
        return CheckTwingateResource(resourceName, func(res *model.Resource) error {
5✔
380
                if res.UsageBasedAutolockDurationDays == nil {
2✔
381
                        return fmt.Errorf("expected usage based duration %v, got <nil>", expectedUsageBased) //nolint:err113
×
382
                }
×
383

384
                if *res.UsageBasedAutolockDurationDays != expectedUsageBased {
2✔
385
                        return fmt.Errorf("expected usage based duration %v, got %v", expectedUsageBased, *res.UsageBasedAutolockDurationDays) //nolint:err113
×
386
                }
×
387

388
                return nil
2✔
389
        })
390
}
391

392
func CheckTwingateResourceTags(resourceName, tag, expectedValue string) sdk.TestCheckFunc {
3✔
393
        return CheckTwingateResource(resourceName, func(res *model.Resource) error {
5✔
394
                if len(res.Tags) == 0 {
2✔
395
                        return ErrEmptyTagsList
×
396
                }
×
397

398
                if res.Tags[tag] != expectedValue {
2✔
399
                        return fmt.Errorf("expected tag value %v, got %v", expectedValue, res.Tags[tag]) //nolint:err113
×
400
                }
×
401

402
                return nil
2✔
403
        })
404
}
405

406
func CheckTwingateResourceSecurityPolicyIsNullOnGroupAccess(resourceName string) sdk.TestCheckFunc {
2✔
407
        return CheckTwingateResource(resourceName, func(res *model.Resource) error {
4✔
408
                if len(res.GroupsAccess) == 0 {
2✔
409
                        return ErrEmptyGroupAccess
×
410
                }
×
411

412
                if res.GroupsAccess[0].SecurityPolicyID != nil {
2✔
413
                        return ErrNotNullSecurityPolicy
×
414
                }
×
415

416
                return nil
2✔
417
        })
418
}
419

420
func CheckTwingateResourceUsageBasedIsNullOnGroupAccess(resourceName string) sdk.TestCheckFunc {
3✔
421
        return CheckTwingateResource(resourceName, func(res *model.Resource) error {
5✔
422
                if len(res.GroupsAccess) == 0 {
2✔
423
                        return ErrEmptyGroupAccess
×
424
                }
×
425

426
                if res.GroupsAccess[0].UsageBasedDuration != nil {
2✔
427
                        return ErrNotNullUsageBased
×
428
                }
×
429

430
                return nil
2✔
431
        })
432
}
433

434
func CheckTwingateResourceUsageBasedIsNullOnResource(resourceName string) sdk.TestCheckFunc {
3✔
435
        return CheckTwingateResource(resourceName, func(res *model.Resource) error {
5✔
436
                if res.UsageBasedAutolockDurationDays != nil {
2✔
437
                        return ErrNotNullUsageBasedOnResource
×
438
                }
×
439

440
                return nil
2✔
441
        })
442
}
443

444
func CheckTwingateResourceActiveState(resourceName string, expectedActiveState bool) sdk.TestCheckFunc {
3✔
445
        return CheckTwingateResource(resourceName, func(res *model.Resource) error {
5✔
446
                if res.IsActive != expectedActiveState {
2✔
447
                        return fmt.Errorf("expected active state %v, got %v", expectedActiveState, res.IsActive) //nolint:err113
×
448
                }
×
449

450
                return nil
2✔
451
        })
452
}
453

454
type checkResourceActiveState struct {
455
        resourceAddress     string
456
        expectedActiveState bool
457
}
458

459
// CheckPlan implements the plan check logic.
460
func (e checkResourceActiveState) CheckPlan(ctx context.Context, req plancheck.CheckPlanRequest, resp *plancheck.CheckPlanResponse) {
2✔
461
        var resourceID string
2✔
462

2✔
463
        for _, rc := range req.Plan.ResourceChanges {
4✔
464
                if e.resourceAddress != rc.Address {
4✔
465
                        continue
2✔
466
                }
467

468
                result, err := tfjsonpath.Traverse(rc.Change.Before, tfjsonpath.New(attr.ID))
2✔
469
                if err != nil {
2✔
470
                        resp.Error = err
×
471

×
472
                        return
×
473
                }
×
474

475
                resultID, ok := result.(string)
2✔
476
                if !ok {
2✔
477
                        resp.Error = ErrInvalidPath
×
478

×
479
                        return
×
480
                }
×
481

482
                resourceID = resultID
2✔
483

2✔
484
                break
2✔
485
        }
486

487
        if resourceID == "" {
2✔
488
                resp.Error = fmt.Errorf("%s - Resource not found in plan ResourceChanges", e.resourceAddress) //nolint:err113
×
489

×
490
                return
×
491
        }
×
492

493
        res, err := providerClient.ReadResource(ctx, resourceID)
2✔
494
        if err != nil {
2✔
495
                resp.Error = fmt.Errorf("failed to read resource: %w", err)
×
496

×
497
                return
×
498
        }
×
499

500
        if res.IsActive != e.expectedActiveState {
2✔
501
                resp.Error = fmt.Errorf("expected active state %v, got %v", e.expectedActiveState, res.IsActive) //nolint:err113
×
502

×
503
                return
×
504
        }
×
505
}
506

507
func CheckResourceActiveState(resourceAddress string, activeState bool) plancheck.PlanCheck {
3✔
508
        return checkResourceActiveState{
3✔
509
                resourceAddress:     resourceAddress,
3✔
510
                expectedActiveState: activeState,
3✔
511
        }
3✔
512
}
3✔
513

514
func CheckImportState(attributes map[string]string) func(data []*terraform.InstanceState) error {
3✔
515
        return func(data []*terraform.InstanceState) error {
5✔
516
                if len(data) != 1 {
2✔
517
                        return fmt.Errorf("expected 1 resource, got %d", len(data)) //nolint:err113
×
518
                }
×
519

520
                res := data[0]
2✔
521
                for name, expected := range attributes {
4✔
522
                        if res.Attributes[name] != expected {
2✔
523
                                return fmt.Errorf("attribute %s doesn't match, expected: %s, got: %s", name, expected, res.Attributes[name]) //nolint:err113
×
524
                        }
×
525
                }
526

527
                return nil
2✔
528
        }
529
}
530

531
func CheckTwingateRemoteNetworkDestroy(s *terraform.State) error {
2✔
532
        for _, rs := range s.RootModule().Resources {
4✔
533
                if rs.Type != resource.TwingateRemoteNetwork {
4✔
534
                        continue
2✔
535
                }
536

537
                remoteNetworkID := rs.Primary.ID
2✔
538

2✔
539
                remoteNetwork, _ := providerClient.ReadRemoteNetworkByID(context.Background(), remoteNetworkID)
2✔
540
                if remoteNetwork != nil {
2✔
541
                        return fmt.Errorf("%w with ID %s", ErrResourceStillPresent, remoteNetworkID)
×
542
                }
×
543
        }
544

545
        return nil
2✔
546
}
547

548
func CheckTwingateGroupDestroy(s *terraform.State) error {
2✔
549
        for _, rs := range s.RootModule().Resources {
4✔
550
                if rs.Type != resource.TwingateGroup {
4✔
551
                        continue
2✔
552
                }
553

554
                groupID := rs.Primary.ID
2✔
555

2✔
556
                group, _ := providerClient.ReadGroup(context.Background(), groupID)
2✔
557
                if group != nil {
2✔
558
                        return fmt.Errorf("%w with ID %s", ErrResourceStillPresent, groupID)
×
559
                }
×
560
        }
561

562
        return nil
2✔
563
}
564

565
func CheckTwingateConnectorDestroy(s *terraform.State) error {
2✔
566
        for _, rs := range s.RootModule().Resources {
4✔
567
                if rs.Type != resource.TwingateConnector {
4✔
568
                        continue
2✔
569
                }
570

571
                connectorID := rs.Primary.ID
2✔
572

2✔
573
                connector, _ := providerClient.ReadConnector(context.Background(), connectorID)
2✔
574
                if connector != nil {
2✔
575
                        return fmt.Errorf("%w with ID %s", ErrResourceStillPresent, connectorID)
×
576
                }
×
577
        }
578

579
        return nil
2✔
580
}
581

582
func CheckTwingateDNSProfileDestroy(s *terraform.State) error {
2✔
583
        for _, rs := range s.RootModule().Resources {
4✔
584
                if rs.Type != resource.TwingateDNSFilteringProfile {
4✔
585
                        continue
2✔
586
                }
587

588
                profileID := rs.Primary.ID
2✔
589

2✔
590
                profile, _ := providerClient.ReadDNSFilteringProfile(context.Background(), profileID)
2✔
591
                if profile != nil {
2✔
592
                        return fmt.Errorf("%w with ID %s", ErrResourceStillPresent, profileID)
×
593
                }
×
594
        }
595

596
        return nil
2✔
597
}
598

599
func RevokeTwingateServiceKey(resourceName string) sdk.TestCheckFunc {
3✔
600
        return func(s *terraform.State) error {
5✔
601
                resourceState, ok := s.RootModule().Resources[resourceName]
2✔
602
                if !ok {
2✔
603
                        return fmt.Errorf("%w: %s", ErrResourceNotFound, resourceName)
×
604
                }
×
605

606
                resourceID := resourceState.Primary.ID
2✔
607
                if resourceID == "" {
2✔
608
                        return ErrResourceIDNotSet
×
609
                }
×
610

611
                err := providerClient.RevokeServiceKey(context.Background(), resourceID)
2✔
612
                if err != nil {
2✔
613
                        return fmt.Errorf("failed to revoke service account key with ID %s: %w", resourceID, err)
×
614
                }
×
615

616
                return nil
2✔
617
        }
618
}
619

620
func CheckTwingateServiceKeyStatus(resourceName string, expectedStatus string) sdk.TestCheckFunc {
3✔
621
        return func(s *terraform.State) error {
5✔
622
                resourceState, ok := s.RootModule().Resources[resourceName]
2✔
623
                if !ok {
2✔
624
                        return fmt.Errorf("%w: %s", ErrResourceNotFound, resourceName)
×
625
                }
×
626

627
                if resourceState.Primary.ID == "" {
2✔
628
                        return ErrResourceIDNotSet
×
629
                }
×
630

631
                serviceAccountKey, err := providerClient.ReadServiceKey(context.Background(), resourceState.Primary.ID)
2✔
632
                if err != nil {
2✔
633
                        return fmt.Errorf("failed to read service account key with ID %s: %w", resourceState.Primary.ID, err)
×
634
                }
×
635

636
                if serviceAccountKey.Status != expectedStatus {
2✔
637
                        return fmt.Errorf("expected status %v, got %v", expectedStatus, serviceAccountKey.Status) //nolint:err113
×
638
                }
×
639

640
                return nil
2✔
641
        }
642
}
643

644
func ListSecurityPolicies() ([]*model.SecurityPolicy, error) {
3✔
645
        if providerClient == nil {
3✔
646
                return nil, ErrClientNotInitialized
×
647
        }
×
648

649
        securityPolicies, err := providerClient.ReadSecurityPolicies(context.Background(), "", "")
3✔
650
        if err != nil {
4✔
651
                return nil, fmt.Errorf("failed to fetch all security policies: %w", err)
1✔
652
        }
1✔
653

654
        if len(securityPolicies) == 0 {
2✔
655
                return nil, ErrSecurityPoliciesNotFound
×
656
        }
×
657

658
        return securityPolicies, nil
2✔
659
}
660

661
func AddResourceGroup(resourceName, groupName string) sdk.TestCheckFunc {
3✔
662
        return func(state *terraform.State) error {
5✔
663
                resourceID, err := getResourceID(state, resourceName)
2✔
664
                if err != nil {
2✔
665
                        return err
×
666
                }
×
667

668
                groupID, err := getResourceID(state, groupName)
2✔
669
                if err != nil {
2✔
670
                        return err
×
671
                }
×
672

673
                err = providerClient.AddResourceAccess(context.Background(), resourceID, []client.AccessInput{
2✔
674
                        {PrincipalID: groupID},
2✔
675
                })
2✔
676
                if err != nil {
2✔
677
                        return fmt.Errorf("resource with ID %s failed to add group with ID %s: %w", resourceID, groupID, err)
×
678
                }
×
679

680
                return nil
2✔
681
        }
682
}
683

684
func DeleteResourceGroup(resourceName, groupName string) sdk.TestCheckFunc {
3✔
685
        return func(state *terraform.State) error {
5✔
686
                resourceID, err := getResourceID(state, resourceName)
2✔
687
                if err != nil {
2✔
688
                        return err
×
689
                }
×
690

691
                groupID, err := getResourceID(state, groupName)
2✔
692
                if err != nil {
2✔
693
                        return err
×
694
                }
×
695

696
                err = providerClient.RemoveResourceAccess(context.Background(), resourceID, []string{groupID})
2✔
697
                if err != nil {
2✔
698
                        return fmt.Errorf("resource with ID %s failed to delete group with ID %s: %w", resourceID, groupID, err)
×
699
                }
×
700

701
                return nil
2✔
702
        }
703
}
704

705
func CheckResourceGroupsLen(resourceName string, expectedGroupsLen int) sdk.TestCheckFunc {
3✔
706
        return func(state *terraform.State) error {
5✔
707
                resourceID, err := getResourceID(state, resourceName)
2✔
708
                if err != nil {
2✔
709
                        return err
×
710
                }
×
711

712
                resource, err := providerClient.ReadResource(context.Background(), resourceID)
2✔
713
                if err != nil {
2✔
714
                        return fmt.Errorf("resource with ID %s failed to read: %w", resourceID, err)
×
715
                }
×
716

717
                if len(resource.GroupsAccess) != expectedGroupsLen {
2✔
718
                        return ErrGroupsLenMismatch(expectedGroupsLen, len(resource.GroupsAccess))
×
719
                }
×
720

721
                return nil
2✔
722
        }
723
}
724

725
func getResourceID(s *terraform.State, resourceName string) (string, error) {
2✔
726
        resourceState, ok := s.RootModule().Resources[resourceName]
2✔
727

2✔
728
        if !ok {
2✔
729
                return "", fmt.Errorf("%w: %s", ErrResourceNotFound, resourceName)
×
730
        }
×
731

732
        resourceID := resourceState.Primary.ID
2✔
733

2✔
734
        if resourceID == "" {
2✔
735
                return "", ErrResourceIDNotSet
×
736
        }
×
737

738
        return resourceID, nil
2✔
739
}
740

741
func AddResourceServiceAccount(resourceName, serviceAccountName string) sdk.TestCheckFunc {
3✔
742
        return func(state *terraform.State) error {
5✔
743
                resourceID, err := getResourceID(state, resourceName)
2✔
744
                if err != nil {
2✔
745
                        return err
×
746
                }
×
747

748
                serviceAccountID, err := getResourceID(state, serviceAccountName)
2✔
749
                if err != nil {
2✔
750
                        return err
×
751
                }
×
752

753
                err = providerClient.AddResourceAccess(context.Background(), resourceID, []client.AccessInput{
2✔
754
                        {PrincipalID: serviceAccountID},
2✔
755
                })
2✔
756
                if err != nil {
2✔
757
                        return fmt.Errorf("resource with ID %s failed to add service account with ID %s: %w", resourceID, serviceAccountID, err)
×
758
                }
×
759

760
                return nil
2✔
761
        }
762
}
763

764
func AddDNSProfileAllowedDomains(resourceName string, domains []string) sdk.TestCheckFunc {
3✔
765
        return func(state *terraform.State) error {
5✔
766
                profileID, err := getResourceID(state, resourceName)
2✔
767
                if err != nil {
2✔
768
                        return err
×
769
                }
×
770

771
                profile, err := providerClient.ReadDNSFilteringProfile(context.Background(), profileID)
2✔
772
                if err != nil {
2✔
773
                        return fmt.Errorf("failed to fetch DNS profile with ID %s: %w", profileID, err)
×
774
                }
×
775

776
                profile.AllowedDomains = domains
2✔
777

2✔
778
                _, err = providerClient.UpdateDNSFilteringProfile(context.Background(), profile)
2✔
779
                if err != nil {
2✔
780
                        return fmt.Errorf("DNS profile with ID %s failed to set new domains: %w", profileID, err)
×
781
                }
×
782

783
                return nil
2✔
784
        }
785
}
786

787
func DeleteResourceServiceAccount(resourceName, serviceAccountName string) sdk.TestCheckFunc {
3✔
788
        return func(state *terraform.State) error {
5✔
789
                resourceID, err := getResourceID(state, resourceName)
2✔
790
                if err != nil {
2✔
791
                        return err
×
792
                }
×
793

794
                serviceAccountID, err := getResourceID(state, serviceAccountName)
2✔
795
                if err != nil {
2✔
796
                        return err
×
797
                }
×
798

799
                err = providerClient.RemoveResourceAccess(context.Background(), resourceID, []string{serviceAccountID})
2✔
800
                if err != nil {
2✔
801
                        return fmt.Errorf("resource with ID %s failed to delete service account with ID %s: %w", resourceID, serviceAccountID, err)
×
802
                }
×
803

804
                return nil
2✔
805
        }
806
}
807

808
func CheckResourceServiceAccountsLen(resourceName string, expectedServiceAccountsLen int) sdk.TestCheckFunc {
3✔
809
        return func(state *terraform.State) error {
5✔
810
                resourceID, err := getResourceID(state, resourceName)
2✔
811
                if err != nil {
2✔
812
                        return err
×
813
                }
×
814

815
                resource, err := providerClient.ReadResource(context.Background(), resourceID)
2✔
816
                if err != nil {
2✔
817
                        return fmt.Errorf("resource with ID %s failed to read: %w", resourceID, err)
×
818
                }
×
819

820
                if len(resource.ServiceAccounts) != expectedServiceAccountsLen {
2✔
821
                        return ErrServiceAccountsLenMismatch(expectedServiceAccountsLen, len(resource.ServiceAccounts))
×
822
                }
×
823

824
                return nil
2✔
825
        }
826
}
827

828
func CheckDNSProfileAllowedDomainsLen(resourceName string, expectedLen int) sdk.TestCheckFunc {
3✔
829
        return func(state *terraform.State) error {
5✔
830
                resourceID, err := getResourceID(state, resourceName)
2✔
831
                if err != nil {
2✔
832
                        return err
×
833
                }
×
834

835
                profile, err := providerClient.ReadDNSFilteringProfile(context.Background(), resourceID)
2✔
836
                if err != nil {
2✔
837
                        return fmt.Errorf("profile with ID %s failed to read: %w", resourceID, err)
×
838
                }
×
839

840
                if len(profile.AllowedDomains) != expectedLen {
2✔
841
                        return ErrDNSProfileAllowedDomainsLenMismatch(expectedLen, len(profile.AllowedDomains))
×
842
                }
×
843

844
                return nil
2✔
845
        }
846
}
847

848
func CheckResourceSecurityPolicy(resourceName string, expectedSecurityPolicyID string) sdk.TestCheckFunc {
2✔
849
        return func(state *terraform.State) error {
4✔
850
                resourceID, err := getResourceID(state, resourceName)
2✔
851
                if err != nil {
2✔
852
                        return err
×
853
                }
×
854

855
                resource, err := providerClient.ReadResource(context.Background(), resourceID)
2✔
856
                if err != nil {
2✔
857
                        return fmt.Errorf("resource with ID %s failed to read: %w", resourceID, err)
×
858
                }
×
859

860
                if resource.SecurityPolicyID != nil && *resource.SecurityPolicyID != expectedSecurityPolicyID {
2✔
861
                        return fmt.Errorf("expected security_policy_id %s, got %s", expectedSecurityPolicyID, *resource.SecurityPolicyID) //nolint
×
862
                }
×
863

864
                return nil
2✔
865
        }
866
}
867

868
func CheckConnectorName(resourceName string, expectedName string) sdk.TestCheckFunc {
3✔
869
        return func(s *terraform.State) error {
5✔
870
                resourceState, ok := s.RootModule().Resources[resourceName]
2✔
871

2✔
872
                if !ok {
2✔
873
                        return fmt.Errorf("%w: %s", ErrResourceNotFound, resourceName)
×
874
                }
×
875

876
                if resourceState.Primary.ID == "" {
2✔
877
                        return ErrResourceIDNotSet
×
878
                }
×
879

880
                connector, err := providerClient.ReadConnector(context.Background(), resourceState.Primary.ID)
2✔
881
                if err != nil {
2✔
882
                        return fmt.Errorf("failed to read connector: %w", err)
×
883
                }
×
884

885
                if connector.Name != expectedName {
2✔
886
                        return fmt.Errorf("expected name %v, got %v", expectedName, connector.Name) //nolint:err113
×
887
                }
×
888

889
                return nil
2✔
890
        }
891
}
892

893
func UpdateResourceSecurityPolicy(resourceName, securityPolicyID string) sdk.TestCheckFunc {
2✔
894
        return func(state *terraform.State) error {
4✔
895
                resourceID, err := getResourceID(state, resourceName)
2✔
896
                if err != nil {
2✔
897
                        return err
×
898
                }
×
899

900
                resource, err := providerClient.ReadResource(context.Background(), resourceID)
2✔
901
                if err != nil {
2✔
902
                        return fmt.Errorf("resource with ID %s failed to read: %w", resourceID, err)
×
903
                }
×
904

905
                resource.SecurityPolicyID = &securityPolicyID
2✔
906

2✔
907
                _, err = providerClient.UpdateResource(context.Background(), resource)
2✔
908
                if err != nil {
2✔
909
                        return fmt.Errorf("resource with ID %s failed to update security_policy: %w", resourceID, err)
×
910
                }
×
911

912
                return nil
2✔
913
        }
914
}
915

916
func AddGroupUser(groupResource, groupName, terraformUserID string) sdk.TestCheckFunc {
3✔
917
        return func(state *terraform.State) error {
5✔
918
                userID, err := getResourceID(state, getResourceNameFromID(terraformUserID))
2✔
919
                if err != nil {
2✔
920
                        return err
×
921
                }
×
922

923
                resourceID, err := getResourceID(state, groupResource)
2✔
924
                if err != nil {
2✔
925
                        return err
×
926
                }
×
927

928
                _, err = providerClient.UpdateGroup(context.Background(), &model.Group{
2✔
929
                        ID:    resourceID,
2✔
930
                        Name:  groupName,
2✔
931
                        Users: []string{userID},
2✔
932
                })
2✔
933
                if err != nil {
2✔
934
                        return fmt.Errorf("group with ID %s failed to add user with ID %s: %w", resourceID, userID, err)
×
935
                }
×
936

937
                return nil
2✔
938
        }
939
}
940

941
func getResourceNameFromID(terraformID string) string {
2✔
942
        return strings.TrimSuffix(terraformID, ".id")
2✔
943
}
2✔
944

945
func DeleteGroupUser(groupResource, terraformUserID string) sdk.TestCheckFunc {
3✔
946
        return func(state *terraform.State) error {
5✔
947
                userID, err := getResourceID(state, getResourceNameFromID(terraformUserID))
2✔
948
                if err != nil {
2✔
949
                        return err
×
950
                }
×
951

952
                groupID, err := getResourceID(state, groupResource)
2✔
953
                if err != nil {
2✔
954
                        return err
×
955
                }
×
956

957
                err = providerClient.DeleteGroupUsers(context.Background(), groupID, []string{userID})
2✔
958
                if err != nil {
2✔
959
                        return fmt.Errorf("group with ID %s failed to delete user with ID %s: %w", groupID, userID, err)
×
960
                }
×
961

962
                return nil
2✔
963
        }
964
}
965

966
func CheckGroupUsersLen(resourceName string, expectedUsersLen int) sdk.TestCheckFunc {
3✔
967
        return func(state *terraform.State) error {
5✔
968
                groupID, err := getResourceID(state, resourceName)
2✔
969
                if err != nil {
2✔
970
                        return err
×
971
                }
×
972

973
                group, err := providerClient.ReadGroup(context.Background(), groupID)
2✔
974
                if err != nil {
2✔
975
                        return fmt.Errorf("group with ID %s failed to read: %w", groupID, err)
×
976
                }
×
977

978
                if len(group.Users) != expectedUsersLen {
2✔
979
                        return ErrUsersLenMismatch(expectedUsersLen, len(group.Users))
×
980
                }
×
981

982
                return nil
2✔
983
        }
984
}
985

986
func GetTestUsers() ([]*model.User, error) {
3✔
987
        if providerClient == nil {
3✔
988
                return nil, ErrClientNotInitialized
×
989
        }
×
990

991
        users, err := providerClient.ReadUsers(context.Background(), nil)
3✔
992
        if err != nil {
4✔
993
                return nil, err //nolint
1✔
994
        }
1✔
995

996
        if len(users) == 0 {
2✔
997
                return nil, ErrResourceNotFound
×
998
        }
×
999

1000
        return users, nil
2✔
1001
}
1002

1003
func CheckTwingateUserDestroy(s *terraform.State) error {
2✔
1004
        for _, rs := range s.RootModule().Resources {
4✔
1005
                if rs.Type != resource.TwingateUser {
2✔
1006
                        continue
×
1007
                }
1008

1009
                userID := rs.Primary.ID
2✔
1010

2✔
1011
                user, _ := providerClient.ReadUser(context.Background(), userID)
2✔
1012
                if user != nil {
2✔
1013
                        return fmt.Errorf("%w with ID %s", ErrResourceStillPresent, userID)
×
1014
                }
×
1015
        }
1016

1017
        return nil
2✔
1018
}
1019

1020
func CheckTwingateConnectorTokensInvalidated(s *terraform.State) error {
2✔
1021
        for _, res := range s.RootModule().Resources {
4✔
1022
                if res.Type != resource.TwingateConnectorTokens {
4✔
1023
                        continue
2✔
1024
                }
1025

1026
                connectorID := res.Primary.ID
2✔
1027
                accessToken := res.Primary.Attributes[attr.AccessToken]
2✔
1028
                refreshToken := res.Primary.Attributes[attr.RefreshToken]
2✔
1029

2✔
1030
                err := providerClient.VerifyConnectorTokens(context.Background(), refreshToken, accessToken)
2✔
1031
                // expecting error here, since tokens invalidated
2✔
1032
                if err == nil {
2✔
1033
                        return fmt.Errorf("%w with ID %s", ErrResourceStillPresent, connectorID)
×
1034
                }
×
1035
        }
1036

1037
        return nil
2✔
1038
}
1039

1040
func GetTestUser() (*model.User, error) {
3✔
1041
        if providerClient == nil {
3✔
1042
                return nil, ErrClientNotInitialized
×
1043
        }
×
1044

1045
        users, err := providerClient.ReadUsers(context.Background(), nil)
3✔
1046
        if err != nil {
4✔
1047
                return nil, fmt.Errorf("failed to get test users: %w", err)
1✔
1048
        }
1✔
1049

1050
        if len(users) == 0 {
2✔
1051
                return nil, ErrResourceNotFound
×
1052
        }
×
1053

1054
        return users[0], nil
2✔
1055
}
1056

1057
func CheckTwingateConnectorAndRemoteNetworkDestroy(s *terraform.State) error {
2✔
1058
        if err := CheckTwingateConnectorDestroy(s); err != nil {
2✔
1059
                return err
×
1060
        }
×
1061

1062
        return CheckTwingateRemoteNetworkDestroy(s)
2✔
1063
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc