diff --git a/github/resource_github_actions_environment_secret.go b/github/resource_github_actions_environment_secret.go index 1558084996..e8950dc735 100644 --- a/github/resource_github_actions_environment_secret.go +++ b/github/resource_github_actions_environment_secret.go @@ -154,41 +154,7 @@ func resourceGithubActionsEnvironmentSecretRead(d *schema.ResourceData, meta int return err } - if err = d.Set("encrypted_value", d.Get("encrypted_value")); err != nil { - return err - } - if err = d.Set("plaintext_value", d.Get("plaintext_value")); err != nil { - return err - } - if err = d.Set("created_at", secret.CreatedAt.String()); err != nil { - return err - } - - // This is a drift detection mechanism based on timestamps. - // - // If we do not currently store the "updated_at" field, it means we've only - // just created the resource and the value is most likely what we want it to - // be. - // - // If the resource is changed externally in the meantime then reading back - // the last update timestamp will return a result different than the - // timestamp we've persisted in the state. In that case, we can no longer - // trust that the value (which we don't see) is equal to what we've declared - // previously. - // - // The only solution to enforce consistency between is to mark the resource - // as deleted (unset the ID) in order to fix potential drift by recreating - // the resource. - if updatedAt, ok := d.GetOk("updated_at"); ok && updatedAt != secret.UpdatedAt.String() { - log.Printf("[INFO] The environment secret %s has been externally updated in GitHub", d.Id()) - d.SetId("") - } else if !ok { - if err = d.Set("updated_at", secret.UpdatedAt.String()); err != nil { - return err - } - } - - return nil + return readMaybeDriftedSecret(d, secret) } func resourceGithubActionsEnvironmentSecretDelete(d *schema.ResourceData, meta interface{}) error { diff --git a/github/resource_github_actions_organization_secret.go b/github/resource_github_actions_organization_secret.go index 4c196f218d..a0713bd6ce 100644 --- a/github/resource_github_actions_organization_secret.go +++ b/github/resource_github_actions_organization_secret.go @@ -159,15 +159,6 @@ func resourceGithubActionsOrganizationSecretRead(d *schema.ResourceData, meta in return err } - if err = d.Set("encrypted_value", d.Get("encrypted_value")); err != nil { - return err - } - if err = d.Set("plaintext_value", d.Get("plaintext_value")); err != nil { - return err - } - if err = d.Set("created_at", secret.CreatedAt.String()); err != nil { - return err - } if err = d.Set("visibility", secret.Visibility); err != nil { return err } @@ -199,31 +190,7 @@ func resourceGithubActionsOrganizationSecretRead(d *schema.ResourceData, meta in return err } - // This is a drift detection mechanism based on timestamps. - // - // If we do not currently store the "updated_at" field, it means we've only - // just created the resource and the value is most likely what we want it to - // be. - // - // If the resource is changed externally in the meantime then reading back - // the last update timestamp will return a result different than the - // timestamp we've persisted in the state. In that case, we can no longer - // trust that the value (which we don't see) is equal to what we've declared - // previously. - // - // The only solution to enforce consistency between is to mark the resource - // as deleted (unset the ID) in order to fix potential drift by recreating - // the resource. - if updatedAt, ok := d.GetOk("updated_at"); ok && updatedAt != secret.UpdatedAt.String() { - log.Printf("[INFO] The secret %s has been externally updated in GitHub", d.Id()) - d.SetId("") - } else if !ok { - if err = d.Set("updated_at", secret.UpdatedAt.String()); err != nil { - return err - } - } - - return nil + return readMaybeDriftedSecret(d, secret) } func resourceGithubActionsOrganizationSecretDelete(d *schema.ResourceData, meta interface{}) error { diff --git a/github/resource_github_actions_secret.go b/github/resource_github_actions_secret.go index 79fea4f729..0cc57ed8a9 100644 --- a/github/resource_github_actions_secret.go +++ b/github/resource_github_actions_secret.go @@ -130,41 +130,7 @@ func resourceGithubActionsSecretRead(d *schema.ResourceData, meta interface{}) e return err } - if err = d.Set("encrypted_value", d.Get("encrypted_value")); err != nil { - return err - } - if err = d.Set("plaintext_value", d.Get("plaintext_value")); err != nil { - return err - } - if err = d.Set("created_at", secret.CreatedAt.String()); err != nil { - return err - } - - // This is a drift detection mechanism based on timestamps. - // - // If we do not currently store the "updated_at" field, it means we've only - // just created the resource and the value is most likely what we want it to - // be. - // - // If the resource is changed externally in the meantime then reading back - // the last update timestamp will return a result different than the - // timestamp we've persisted in the state. In that case, we can no longer - // trust that the value (which we don't see) is equal to what we've declared - // previously. - // - // The only solution to enforce consistency between is to mark the resource - // as deleted (unset the ID) in order to fix potential drift by recreating - // the resource. - if updatedAt, ok := d.GetOk("updated_at"); ok && updatedAt != secret.UpdatedAt.String() { - log.Printf("[INFO] The secret %s has been externally updated in GitHub", d.Id()) - d.SetId("") - } else if !ok { - if err = d.Set("updated_at", secret.UpdatedAt.String()); err != nil { - return err - } - } - - return nil + return readMaybeDriftedSecret(d, secret) } func resourceGithubActionsSecretDelete(d *schema.ResourceData, meta interface{}) error { diff --git a/github/resource_github_codespaces_organization_secret.go b/github/resource_github_codespaces_organization_secret.go index 95e997a330..6a88603238 100644 --- a/github/resource_github_codespaces_organization_secret.go +++ b/github/resource_github_codespaces_organization_secret.go @@ -159,15 +159,6 @@ func resourceGithubCodespacesOrganizationSecretRead(d *schema.ResourceData, meta return err } - if err = d.Set("encrypted_value", d.Get("encrypted_value")); err != nil { - return err - } - if err = d.Set("plaintext_value", d.Get("plaintext_value")); err != nil { - return err - } - if err = d.Set("created_at", secret.CreatedAt.String()); err != nil { - return err - } if err = d.Set("visibility", secret.Visibility); err != nil { return err } @@ -199,31 +190,7 @@ func resourceGithubCodespacesOrganizationSecretRead(d *schema.ResourceData, meta return err } - // This is a drift detection mechanism based on timestamps. - // - // If we do not currently store the "updated_at" field, it means we've only - // just created the resource and the value is most likely what we want it to - // be. - // - // If the resource is changed externally in the meantime then reading back - // the last update timestamp will return a result different than the - // timestamp we've persisted in the state. In that case, we can no longer - // trust that the value (which we don't see) is equal to what we've declared - // previously. - // - // The only solution to enforce consistency between is to mark the resource - // as deleted (unset the ID) in order to fix potential drift by recreating - // the resource. - if updatedAt, ok := d.GetOk("updated_at"); ok && updatedAt != secret.UpdatedAt.String() { - log.Printf("[WARN] The secret %s has been externally updated in GitHub", d.Id()) - d.SetId("") - } else if !ok { - if err = d.Set("updated_at", secret.UpdatedAt.String()); err != nil { - return err - } - } - - return nil + return readMaybeDriftedSecret(d, secret) } func resourceGithubCodespacesOrganizationSecretDelete(d *schema.ResourceData, meta interface{}) error { diff --git a/github/resource_github_codespaces_secret.go b/github/resource_github_codespaces_secret.go index 0090bb970c..b1341cdb7c 100644 --- a/github/resource_github_codespaces_secret.go +++ b/github/resource_github_codespaces_secret.go @@ -129,41 +129,7 @@ func resourceGithubCodespacesSecretRead(d *schema.ResourceData, meta interface{} return err } - if err = d.Set("encrypted_value", d.Get("encrypted_value")); err != nil { - return err - } - if err = d.Set("plaintext_value", d.Get("plaintext_value")); err != nil { - return err - } - if err = d.Set("created_at", secret.CreatedAt.String()); err != nil { - return err - } - - // This is a drift detection mechanism based on timestamps. - // - // If we do not currently store the "updated_at" field, it means we've only - // just created the resource and the value is most likely what we want it to - // be. - // - // If the resource is changed externally in the meantime then reading back - // the last update timestamp will return a result different than the - // timestamp we've persisted in the state. In that case, we can no longer - // trust that the value (which we don't see) is equal to what we've declared - // previously. - // - // The only solution to enforce consistency between is to mark the resource - // as deleted (unset the ID) in order to fix potential drift by recreating - // the resource. - if updatedAt, ok := d.GetOk("updated_at"); ok && updatedAt != secret.UpdatedAt.String() { - log.Printf("[WARN] The secret %s has been externally updated in GitHub", d.Id()) - d.SetId("") - } else if !ok { - if err = d.Set("updated_at", secret.UpdatedAt.String()); err != nil { - return err - } - } - - return nil + return readMaybeDriftedSecret(d, secret) } func resourceGithubCodespacesSecretDelete(d *schema.ResourceData, meta interface{}) error { diff --git a/github/resource_github_codespaces_user_secret.go b/github/resource_github_codespaces_user_secret.go index dd0fde57ca..1beb83d357 100644 --- a/github/resource_github_codespaces_user_secret.go +++ b/github/resource_github_codespaces_user_secret.go @@ -143,16 +143,6 @@ func resourceGithubCodespacesUserSecretRead(d *schema.ResourceData, meta interfa return err } - if err = d.Set("encrypted_value", d.Get("encrypted_value")); err != nil { - return err - } - if err = d.Set("plaintext_value", d.Get("plaintext_value")); err != nil { - return err - } - if err = d.Set("created_at", secret.CreatedAt.String()); err != nil { - return err - } - selectedRepositoryIDs := []int64{} opt := &github.ListOptions{ @@ -178,31 +168,7 @@ func resourceGithubCodespacesUserSecretRead(d *schema.ResourceData, meta interfa return err } - // This is a drift detection mechanism based on timestamps. - // - // If we do not currently store the "updated_at" field, it means we've only - // just created the resource and the value is most likely what we want it to - // be. - // - // If the resource is changed externally in the meantime then reading back - // the last update timestamp will return a result different than the - // timestamp we've persisted in the state. In that case, we can no longer - // trust that the value (which we don't see) is equal to what we've declared - // previously. - // - // The only solution to enforce consistency between is to mark the resource - // as deleted (unset the ID) in order to fix potential drift by recreating - // the resource. - if updatedAt, ok := d.GetOk("updated_at"); ok && updatedAt != secret.UpdatedAt.String() { - log.Printf("[WARN] The secret %s has been externally updated in GitHub", d.Id()) - d.SetId("") - } else if !ok { - if err = d.Set("updated_at", secret.UpdatedAt.String()); err != nil { - return err - } - } - - return nil + return readMaybeDriftedSecret(d, secret) } func resourceGithubCodespacesUserSecretDelete(d *schema.ResourceData, meta interface{}) error { diff --git a/github/resource_github_dependabot_organization_secret.go b/github/resource_github_dependabot_organization_secret.go index 66d751a313..c758246983 100644 --- a/github/resource_github_dependabot_organization_secret.go +++ b/github/resource_github_dependabot_organization_secret.go @@ -159,15 +159,6 @@ func resourceGithubDependabotOrganizationSecretRead(d *schema.ResourceData, meta return err } - if err = d.Set("encrypted_value", d.Get("encrypted_value")); err != nil { - return err - } - if err = d.Set("plaintext_value", d.Get("plaintext_value")); err != nil { - return err - } - if err = d.Set("created_at", secret.CreatedAt.String()); err != nil { - return err - } if err = d.Set("visibility", secret.Visibility); err != nil { return err } @@ -199,31 +190,7 @@ func resourceGithubDependabotOrganizationSecretRead(d *schema.ResourceData, meta return err } - // This is a drift detection mechanism based on timestamps. - // - // If we do not currently store the "updated_at" field, it means we've only - // just created the resource and the value is most likely what we want it to - // be. - // - // If the resource is changed externally in the meantime then reading back - // the last update timestamp will return a result different than the - // timestamp we've persisted in the state. In that case, we can no longer - // trust that the value (which we don't see) is equal to what we've declared - // previously. - // - // The only solution to enforce consistency between is to mark the resource - // as deleted (unset the ID) in order to fix potential drift by recreating - // the resource. - if updatedAt, ok := d.GetOk("updated_at"); ok && updatedAt != secret.UpdatedAt.String() { - log.Printf("[WARN] The secret %s has been externally updated in GitHub", d.Id()) - d.SetId("") - } else if !ok { - if err = d.Set("updated_at", secret.UpdatedAt.String()); err != nil { - return err - } - } - - return nil + return readMaybeDriftedSecret(d, secret) } func resourceGithubDependabotOrganizationSecretDelete(d *schema.ResourceData, meta interface{}) error { diff --git a/github/resource_github_dependabot_secret.go b/github/resource_github_dependabot_secret.go index f2bc973aa4..f0c6d8c214 100644 --- a/github/resource_github_dependabot_secret.go +++ b/github/resource_github_dependabot_secret.go @@ -140,31 +140,7 @@ func resourceGithubDependabotSecretRead(d *schema.ResourceData, meta interface{} return err } - // This is a drift detection mechanism based on timestamps. - // - // If we do not currently store the "updated_at" field, it means we've only - // just created the resource and the value is most likely what we want it to - // be. - // - // If the resource is changed externally in the meantime then reading back - // the last update timestamp will return a result different than the - // timestamp we've persisted in the state. In that case, we can no longer - // trust that the value (which we don't see) is equal to what we've declared - // previously. - // - // The only solution to enforce consistency between is to mark the resource - // as deleted (unset the ID) in order to fix potential drift by recreating - // the resource. - if updatedAt, ok := d.GetOk("updated_at"); ok && updatedAt != secret.UpdatedAt.String() { - log.Printf("[WARN] The secret %s has been externally updated in GitHub", d.Id()) - d.SetId("") - } else if !ok { - if err = d.Set("updated_at", secret.UpdatedAt.String()); err != nil { - return err - } - } - - return nil + return readMaybeDriftedSecret(d, secret) } func resourceGithubDependabotSecretDelete(d *schema.ResourceData, meta interface{}) error { diff --git a/github/util.go b/github/util.go index 321a201fb4..e9edfe6711 100644 --- a/github/util.go +++ b/github/util.go @@ -263,6 +263,36 @@ func validateSecretNameFunc(v interface{}, path cty.Path) diag.Diagnostics { return wrapErrors(errs) } +// This function is used to read the properties of a secret that may have drifted. +// +// It uses "updated_at" to determine if the secret has been updated externally. If yes, +// it will mark the encrypted values as unset, to force an update. +// +// This is necessary because "encrypted_value" and "plaintext_value" are +// not available to us from the API, as they are write-only on GitHub. +func readMaybeDriftedSecret(d *schema.ResourceData, secret *github.Secret) error { + if err := d.Set("encrypted_value", d.Get("encrypted_value")); err != nil { + return err + } + if err := d.Set("plaintext_value", d.Get("plaintext_value")); err != nil { + return err + } + if err := d.Set("created_at", secret.CreatedAt.String()); err != nil { + return err + } + + if updatedAt, ok := d.GetOk("updated_at"); ok && updatedAt != secret.UpdatedAt.String() { + log.Printf("[INFO] The secret %s has been externally updated in GitHub", d.Id()) + d.Set("encrypted_value", "") + d.Set("plaintext_value", "") + } else if !ok { + if err := d.Set("updated_at", secret.UpdatedAt.String()); err != nil { + return err + } + } + return nil +} + // deleteResourceOn404AndSwallow304OtherwiseReturnError will log and delete resource if error is 404 which indicates resource (or any of its ancestors) // doesn't exist. // resourceDescription represents a formatting string that represents the resource