Skip to content

Commit 1ae026c

Browse files
committed
Updates how we handle secrets to address provider config issues
1 parent 974120c commit 1ae026c

7 files changed

+39
-40
lines changed

github/resource_github_actions_organization_secret.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ func resourceGithubActionsOrganizationSecret() *schema.Resource {
5959
"visibility": {
6060
Type: schema.TypeString,
6161
Required: true,
62-
ValidateDiagFunc: validateValueFunc([]string{"all", "private", "selected"}),
6362
ForceNew: true,
63+
ValidateDiagFunc: validateValueFunc([]string{"all", "private", "selected"}),
6464
Description: "Configures the access that repositories have to the organization secret. Must be one of 'all', 'private', or 'selected'. 'selected_repository_ids' is required if set to 'selected'.",
6565
},
6666
"selected_repository_ids": {
@@ -218,10 +218,10 @@ func resourceGithubActionsOrganizationSecretRead(d *schema.ResourceData, meta in
218218
// previously.
219219
destroyOnDrift := d.Get("destroy_on_drift").(bool)
220220
storedUpdatedAt, hasStoredUpdatedAt := d.GetOk("updated_at")
221-
221+
222222
if hasStoredUpdatedAt && storedUpdatedAt != secret.UpdatedAt.String() {
223223
log.Printf("[INFO] The secret %s has been externally updated in GitHub", d.Id())
224-
224+
225225
if destroyOnDrift {
226226
// Original behavior: mark for recreation
227227
d.SetId("")

github/resource_github_actions_organization_secret_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ func TestAccGithubActionsOrganizationSecret(t *testing.T) {
190190
t.Run("destroyOnDrift false clears sensitive values instead of recreating", func(t *testing.T) {
191191
originalTimestamp := "2023-01-01T00:00:00Z"
192192
newTimestamp := "2023-01-02T00:00:00Z"
193-
193+
194194
d := schema.TestResourceDataRaw(t, resourceGithubActionsOrganizationSecret().Schema, map[string]interface{}{
195195
"secret_name": "test-secret",
196196
"plaintext_value": "original-value",
@@ -204,7 +204,7 @@ func TestAccGithubActionsOrganizationSecret(t *testing.T) {
204204
// Simulate drift detection logic when destroy_on_drift is false
205205
destroyOnDrift := d.Get("destroy_on_drift").(bool)
206206
storedUpdatedAt, hasStoredUpdatedAt := d.GetOk("updated_at")
207-
207+
208208
if hasStoredUpdatedAt && storedUpdatedAt != newTimestamp {
209209
if destroyOnDrift {
210210
// Would clear ID for recreation
@@ -240,20 +240,20 @@ func TestAccGithubActionsOrganizationSecret(t *testing.T) {
240240
t.Run("destroyOnDrift true still recreates resource on drift", func(t *testing.T) {
241241
originalTimestamp := "2023-01-01T00:00:00Z"
242242
newTimestamp := "2023-01-02T00:00:00Z"
243-
243+
244244
d := schema.TestResourceDataRaw(t, resourceGithubActionsOrganizationSecret().Schema, map[string]interface{}{
245245
"secret_name": "test-secret",
246246
"plaintext_value": "original-value",
247247
"visibility": "private",
248-
"destroy_on_drift": true, // Explicitly set to true
248+
"destroy_on_drift": true, // Explicitly set to true
249249
"updated_at": originalTimestamp,
250250
})
251251
d.SetId("test-secret")
252252

253253
// Simulate drift detection logic when destroy_on_drift is true
254254
destroyOnDrift := d.Get("destroy_on_drift").(bool)
255255
storedUpdatedAt, hasStoredUpdatedAt := d.GetOk("updated_at")
256-
256+
257257
if hasStoredUpdatedAt && storedUpdatedAt != newTimestamp {
258258
if destroyOnDrift {
259259
// Should clear ID for recreation (original behavior)
@@ -262,7 +262,7 @@ func TestAccGithubActionsOrganizationSecret(t *testing.T) {
262262
}
263263
}
264264

265-
// Should have cleared the ID for recreation when destroy_on_drift=true
265+
// Should have cleared the ID for recreation when destroy_on_drift=true
266266
if d.Id() != "" {
267267
t.Error("Expected ID to be cleared for recreation when destroy_on_drift=true, but it was preserved")
268268
}
@@ -278,7 +278,7 @@ func TestAccGithubActionsOrganizationSecret(t *testing.T) {
278278

279279
t.Run("default destroy_on_drift is true", func(t *testing.T) {
280280
d := schema.TestResourceDataRaw(t, resourceGithubActionsOrganizationSecret().Schema, map[string]interface{}{
281-
"secret_name": "test-secret",
281+
"secret_name": "test-secret",
282282
"plaintext_value": "test-value",
283283
"visibility": "private",
284284
// destroy_on_drift not set, should default to true

github/resource_github_actions_secret.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ func resourceGithubActionsSecret() *schema.Resource {
1717
return &schema.Resource{
1818
Create: resourceGithubActionsSecretCreateOrUpdate,
1919
Read: resourceGithubActionsSecretRead,
20-
Update: resourceGithubActionsSecretCreateOrUpdate,
2120
Delete: resourceGithubActionsSecretDelete,
2221
Importer: &schema.ResourceImporter{
2322
State: resourceGithubActionsSecretImport,
@@ -187,7 +186,7 @@ func resourceGithubActionsSecretRead(d *schema.ResourceData, meta interface{}) e
187186
if err = d.Set("plaintext_value", d.Get("plaintext_value")); err != nil {
188187
return err
189188
}
190-
} // Always update the timestamp to prevent repeated drift detection
189+
} // Always update the timestamp to prevent repeated drift detection
191190
if err = d.Set("updated_at", secret.UpdatedAt.String()); err != nil {
192191
return err
193192
}

github/resource_github_actions_secret_test.go

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ func TestAccGithubActionsSecret(t *testing.T) {
298298

299299
t.Run("respects destroy_on_drift setting", func(t *testing.T) {
300300
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
301-
301+
302302
config := fmt.Sprintf(`
303303
resource "github_repository" "test" {
304304
name = "tf-acc-test-%s"
@@ -368,11 +368,11 @@ func TestAccGithubActionsSecret(t *testing.T) {
368368

369369
// Unit tests for drift detection behavior
370370
func TestGithubActionsSecretDriftDetection(t *testing.T) {
371-
371+
372372
t.Run("destroyOnDrift true causes recreation on timestamp mismatch", func(t *testing.T) {
373373
originalTimestamp := "2023-01-01T00:00:00Z"
374374
newTimestamp := "2023-01-02T00:00:00Z"
375-
375+
376376
d := schema.TestResourceDataRaw(t, resourceGithubActionsSecret().Schema, map[string]interface{}{
377377
"repository": "test-repo",
378378
"secret_name": "test-secret",
@@ -397,9 +397,9 @@ func TestGithubActionsSecretDriftDetection(t *testing.T) {
397397
t.Run("destroyOnDrift false clears sensitive values instead of recreating", func(t *testing.T) {
398398
originalTimestamp := "2023-01-01T00:00:00Z"
399399
newTimestamp := "2023-01-02T00:00:00Z"
400-
400+
401401
d := schema.TestResourceDataRaw(t, resourceGithubActionsSecret().Schema, map[string]interface{}{
402-
"repository": "test-repo",
402+
"repository": "test-repo",
403403
"secret_name": "test-secret",
404404
"plaintext_value": "original-value",
405405
"encrypted_value": "original-encrypted",
@@ -411,7 +411,7 @@ func TestGithubActionsSecretDriftDetection(t *testing.T) {
411411
// Simulate drift detection logic when destroy_on_drift is false
412412
destroyOnDrift := d.Get("destroy_on_drift").(bool)
413413
storedUpdatedAt, hasStoredUpdatedAt := d.GetOk("updated_at")
414-
414+
415415
if hasStoredUpdatedAt && storedUpdatedAt != newTimestamp {
416416
if destroyOnDrift {
417417
// Would clear ID for recreation
@@ -447,20 +447,20 @@ func TestGithubActionsSecretDriftDetection(t *testing.T) {
447447
t.Run("destroyOnDrift true still recreates resource on drift", func(t *testing.T) {
448448
originalTimestamp := "2023-01-01T00:00:00Z"
449449
newTimestamp := "2023-01-02T00:00:00Z"
450-
450+
451451
d := schema.TestResourceDataRaw(t, resourceGithubActionsSecret().Schema, map[string]interface{}{
452-
"repository": "test-repo",
452+
"repository": "test-repo",
453453
"secret_name": "test-secret",
454454
"plaintext_value": "original-value",
455-
"destroy_on_drift": true, // Explicitly set to true
455+
"destroy_on_drift": true, // Explicitly set to true
456456
"updated_at": originalTimestamp,
457457
})
458458
d.SetId("test-secret")
459459

460460
// Simulate drift detection logic when destroy_on_drift is true
461461
destroyOnDrift := d.Get("destroy_on_drift").(bool)
462462
storedUpdatedAt, hasStoredUpdatedAt := d.GetOk("updated_at")
463-
463+
464464
if hasStoredUpdatedAt && storedUpdatedAt != newTimestamp {
465465
if destroyOnDrift {
466466
// Should clear ID for recreation (original behavior)
@@ -469,7 +469,7 @@ func TestGithubActionsSecretDriftDetection(t *testing.T) {
469469
}
470470
}
471471

472-
// Should have cleared the ID for recreation when destroy_on_drift=true
472+
// Should have cleared the ID for recreation when destroy_on_drift=true
473473
if d.Id() != "" {
474474
t.Error("Expected ID to be cleared for recreation when destroy_on_drift=true, but it was preserved")
475475
}
@@ -478,7 +478,7 @@ func TestGithubActionsSecretDriftDetection(t *testing.T) {
478478
t.Run("default destroy_on_drift is true", func(t *testing.T) {
479479
d := schema.TestResourceDataRaw(t, resourceGithubActionsSecret().Schema, map[string]interface{}{
480480
"repository": "test-repo",
481-
"secret_name": "test-secret",
481+
"secret_name": "test-secret",
482482
"plaintext_value": "test-value",
483483
// destroy_on_drift not set, should default to true
484484
})
@@ -491,10 +491,10 @@ func TestGithubActionsSecretDriftDetection(t *testing.T) {
491491

492492
t.Run("no drift when timestamps match", func(t *testing.T) {
493493
timestamp := "2023-01-01T00:00:00Z"
494-
494+
495495
d := schema.TestResourceDataRaw(t, resourceGithubActionsSecret().Schema, map[string]interface{}{
496496
"repository": "test-repo",
497-
"secret_name": "test-secret",
497+
"secret_name": "test-secret",
498498
"plaintext_value": "test-value",
499499
"destroy_on_drift": true,
500500
"updated_at": timestamp,
@@ -556,43 +556,43 @@ func TestGithubActionsSecretIssue964Solution(t *testing.T) {
556556
t.Run("solve issue 964 - prevent recreation when GUI changes secret", func(t *testing.T) {
557557
// This test demonstrates the fix for:
558558
// https://github.com/integrations/terraform-provider-github/issues/964
559-
559+
560560
// Scenario: User creates secret with Terraform, then updates value via GitHub GUI
561561
// Expected: With destroy_on_drift=false, Terraform should not recreate the secret
562-
562+
563563
d := schema.TestResourceDataRaw(t, resourceGithubActionsSecret().Schema, map[string]interface{}{
564564
"repository": "my-repo",
565-
"secret_name": "WORKFLOW_PAT",
565+
"secret_name": "WORKFLOW_PAT",
566566
"plaintext_value": "CHANGE_ME", // Initial placeholder value
567-
"destroy_on_drift": false, // KEY FIX: Prevents recreation
567+
"destroy_on_drift": false, // KEY FIX: Prevents recreation
568568
})
569569
d.SetId("WORKFLOW_PAT")
570-
570+
571571
// Set initial timestamp
572572
originalTime := "2023-01-01T00:00:00Z"
573573
d.Set("updated_at", originalTime)
574-
574+
575575
// Simulate: User changes secret value via GitHub GUI
576-
// This changes the updated_at timestamp
576+
// This changes the updated_at timestamp
577577
newTime := "2023-01-01T12:00:00Z" // Later timestamp = external change
578-
578+
579579
// Test the read function behavior - this is what happens during terraform plan/apply
580580
destroyOnDrift := d.Get("destroy_on_drift").(bool) // false
581581
if updatedAt, ok := d.GetOk("updated_at"); ok && !destroyOnDrift && updatedAt != newTime {
582582
// With destroy_on_drift=false, we update timestamp but don't clear ID
583583
d.Set("updated_at", newTime)
584584
}
585-
585+
586586
// RESULT: Secret should NOT be marked for recreation
587587
if d.Id() == "" {
588588
t.Error("ISSUE #964 NOT FIXED: Secret was marked for recreation despite destroy_on_drift=false")
589589
}
590-
590+
591591
// RESULT: Timestamp should be updated to acknowledge the change
592592
if d.Get("updated_at").(string) != newTime {
593593
t.Error("Expected timestamp to be updated to acknowledge external change")
594594
}
595-
595+
596596
t.Logf("SUCCESS: Issue #964 solved - secret with destroy_on_drift=false does not get recreated on external changes")
597597
})
598598
}

github/resource_github_codespaces_organization_secret.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ func resourceGithubCodespacesOrganizationSecret() *schema.Resource {
1616
return &schema.Resource{
1717
Create: resourceGithubCodespacesOrganizationSecretCreateOrUpdate,
1818
Read: resourceGithubCodespacesOrganizationSecretRead,
19-
Update: resourceGithubCodespacesOrganizationSecretCreateOrUpdate,
2019
Delete: resourceGithubCodespacesOrganizationSecretDelete,
2120
Importer: &schema.ResourceImporter{
2221
State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
@@ -66,6 +65,7 @@ func resourceGithubCodespacesOrganizationSecret() *schema.Resource {
6665
},
6766
Set: schema.HashInt,
6867
Optional: true,
68+
ForceNew: true,
6969
Description: "An array of repository ids that can access the organization secret.",
7070
},
7171
"created_at": {

github/resource_github_codespaces_user_secret.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ func resourceGithubCodespacesUserSecret() *schema.Resource {
1515
return &schema.Resource{
1616
Create: resourceGithubCodespacesUserSecretCreateOrUpdate,
1717
Read: resourceGithubCodespacesUserSecretRead,
18-
Update: resourceGithubCodespacesUserSecretCreateOrUpdate,
1918
Delete: resourceGithubCodespacesUserSecretDelete,
2019
Importer: &schema.ResourceImporter{
2120
State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
@@ -58,6 +57,7 @@ func resourceGithubCodespacesUserSecret() *schema.Resource {
5857
},
5958
Set: schema.HashInt,
6059
Optional: true,
60+
ForceNew: true,
6161
Description: "An array of repository ids that can access the user secret.",
6262
},
6363
"created_at": {

github/resource_github_dependabot_organization_secret.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ func resourceGithubDependabotOrganizationSecret() *schema.Resource {
1616
return &schema.Resource{
1717
Create: resourceGithubDependabotOrganizationSecretCreateOrUpdate,
1818
Read: resourceGithubDependabotOrganizationSecretRead,
19-
Update: resourceGithubDependabotOrganizationSecretCreateOrUpdate,
2019
Delete: resourceGithubDependabotOrganizationSecretDelete,
2120
Importer: &schema.ResourceImporter{
2221
State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
@@ -66,6 +65,7 @@ func resourceGithubDependabotOrganizationSecret() *schema.Resource {
6665
},
6766
Set: schema.HashInt,
6867
Optional: true,
68+
ForceNew: true,
6969
Description: "An array of repository ids that can access the organization secret.",
7070
},
7171
"created_at": {

0 commit comments

Comments
 (0)