diff --git a/docs/resources/download_client.md b/docs/resources/download_client.md index cafee550..3c45879d 100644 --- a/docs/resources/download_client.md +++ b/docs/resources/download_client.md @@ -43,7 +43,7 @@ resource "radarr_download_client" "example" { - `add_paused` (Boolean) Add paused flag. - `add_stopped` (Boolean) Add stopped flag. - `additional_tags` (Set of Number) Additional tags, `0` TitleSlug, `1` Quality, `2` Language, `3` ReleaseGroup, `4` Year, `5` Indexer, `6` Network. -- `api_key` (String) API key. +- `api_key` (String, Sensitive) API key. - `api_url` (String) API URL. - `app_id` (String) App ID. - `app_token` (String, Sensitive) App Token. @@ -74,7 +74,7 @@ resource "radarr_download_client" "example" { - `remove_failed_downloads` (Boolean) Remove failed downloads flag. - `rpc_path` (String) RPC path. - `save_magnet_files` (Boolean) Save magnet files flag. -- `secret_token` (String) Secret token. +- `secret_token` (String, Sensitive) Secret token. - `sequential_order` (Boolean) Sequential order flag. - `start_on_add` (Boolean) Start on add flag. - `strm_folder` (String) STRM folder. diff --git a/docs/resources/download_client_aria2.md b/docs/resources/download_client_aria2.md index 8491b5a8..cca24992 100644 --- a/docs/resources/download_client_aria2.md +++ b/docs/resources/download_client_aria2.md @@ -41,7 +41,7 @@ resource "radarr_download_client_aria2" "example" { - `remove_completed_downloads` (Boolean) Remove completed downloads flag. - `remove_failed_downloads` (Boolean) Remove failed downloads flag. - `rpc_path` (String) RPC path. -- `secret_token` (String) Secret token. +- `secret_token` (String, Sensitive) Secret token. - `tags` (Set of Number) List of associated tags. - `use_ssl` (Boolean) Use SSL flag. diff --git a/docs/resources/download_client_nzbvortex.md b/docs/resources/download_client_nzbvortex.md index 1a7b8361..18c1d55d 100644 --- a/docs/resources/download_client_nzbvortex.md +++ b/docs/resources/download_client_nzbvortex.md @@ -30,7 +30,7 @@ resource "radarr_download_client_nzbvortex" "example" { ### Required -- `api_key` (String) API key. +- `api_key` (String, Sensitive) API key. - `name` (String) Download Client name. ### Optional diff --git a/docs/resources/indexer.md b/docs/resources/indexer.md index 7a22c6fa..daccdc6a 100644 --- a/docs/resources/indexer.md +++ b/docs/resources/indexer.md @@ -42,7 +42,7 @@ resource "radarr_indexer" "example" { - `additional_parameters` (String) Additional parameters. - `allow_zero_size` (Boolean) Allow zero size files. -- `api_key` (String) API key. +- `api_key` (String, Sensitive) API key. - `api_path` (String) API path. - `api_user` (String) API User. - `base_url` (String) Base URL. @@ -58,7 +58,7 @@ resource "radarr_indexer" "example" { - `mediums` (Set of Number) Mediumd. - `minimum_seeders` (Number) Minimum seeders. - `multi_languages` (Set of Number) Language list. -- `passkey` (String) Passkey. +- `passkey` (String, Sensitive) Passkey. - `priority` (Number) Priority. - `ranked_only` (Boolean) Allow ranked only. - `remove_year` (Boolean) Remove year. diff --git a/docs/resources/indexer_newznab.md b/docs/resources/indexer_newznab.md index f310fd6a..4f17831a 100644 --- a/docs/resources/indexer_newznab.md +++ b/docs/resources/indexer_newznab.md @@ -35,7 +35,7 @@ resource "radarr_indexer_newznab" "example" { ### Optional - `additional_parameters` (String) Additional parameters. -- `api_key` (String) API key. +- `api_key` (String, Sensitive) API key. - `api_path` (String) API path. - `base_url` (String) Base URL. - `categories` (Set of Number) Series list. diff --git a/docs/resources/notification.md b/docs/resources/notification.md index 8e3e5c0b..cba47816 100644 --- a/docs/resources/notification.md +++ b/docs/resources/notification.md @@ -52,8 +52,8 @@ resource "radarr_notification" "example" { - `access_token` (String) Access token. - `access_token_secret` (String) Access token secret. - `always_update` (Boolean) Always update flag. -- `api_key` (String) API key. -- `app_token` (String) App token. +- `api_key` (String, Sensitive) API key. +- `app_token` (String, Sensitive) App token. - `arguments` (String) Arguments. - `auth_password` (String, Sensitive) Password. - `auth_token` (String) Auth token. @@ -71,7 +71,7 @@ resource "radarr_notification" "example" { - `click_url` (String) Click URL. - `configuration_key` (String, Sensitive) Configuration key. - `consumer_key` (String) Consumer key. -- `consumer_secret` (String) Consumer secret. +- `consumer_secret` (String, Sensitive) Consumer secret. - `device_ids` (Set of String) Device IDs. - `device_names` (String) Device names. - `devices` (Set of String) Devices. diff --git a/internal/helpers/fields.go b/internal/helpers/fields.go index 1caea563..9942ef87 100644 --- a/internal/helpers/fields.go +++ b/internal/helpers/fields.go @@ -12,6 +12,8 @@ import ( "golang.org/x/exp/slices" ) +const SensitiveValue = "********" + type fieldException struct { apiName string tfName string @@ -341,6 +343,13 @@ func WriteFields(ctx context.Context, fieldContainer interface{}, fields []*rada // Loop over each field and populate the related container field with the corresponding write function. for _, f := range fields { fieldName := f.GetName() + // Manage sensitive data. + if f.GetValue() == SensitiveValue { + if tempField := readStringField(fieldName, fieldContainer); tempField.GetValue() != nil { + f = tempField + } + } + for listName, writeFunc := range writeFuncs { if slices.Contains(fieldLists.getList(listName), fieldName) { writeFunc(f, fieldContainer) diff --git a/internal/helpers/fields_test.go b/internal/helpers/fields_test.go index ef751aa3..3ec300a8 100644 --- a/internal/helpers/fields_test.go +++ b/internal/helpers/fields_test.go @@ -607,6 +607,12 @@ func TestWriteFields(t *testing.T) { value: append(make([]interface{}, 0), []string{"test1", "test2"}), fieldContainer: Test{Set: types.SetValueMust(types.StringType, nil)}, }, + "sensitive": { + fieldLists: Fields{Strings: []string{"str"}}, + name: "str", + value: SensitiveValue, + fieldContainer: Test{Str: types.StringValue("String")}, + }, } for name, test := range tests { test := test @@ -624,6 +630,13 @@ func TestWriteFields(t *testing.T) { fields[0].SetValue(test.value) container := Test{} + if test.value == SensitiveValue { + // emulate the sensitive behaviour + container = Test{ + Str: types.StringValue("String"), + } + } + WriteFields(context.TODO(), &container, fields, test.fieldLists) assert.Equal(t, &test.fieldContainer, &container) }) diff --git a/internal/provider/download_client_aria2_resource.go b/internal/provider/download_client_aria2_resource.go index 0596f3bd..779f3dd8 100644 --- a/internal/provider/download_client_aria2_resource.go +++ b/internal/provider/download_client_aria2_resource.go @@ -159,6 +159,7 @@ func (r *DownloadClientAria2Resource) Schema(_ context.Context, _ resource.Schem MarkdownDescription: "Secret token.", Optional: true, Computed: true, + Sensitive: true, }, }, } diff --git a/internal/provider/download_client_freebox_resource_test.go b/internal/provider/download_client_freebox_resource_test.go index 9550ea85..30bdf4a2 100644 --- a/internal/provider/download_client_freebox_resource_test.go +++ b/internal/provider/download_client_freebox_resource_test.go @@ -42,9 +42,10 @@ func TestAccDownloadClientFreeboxResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_download_client_freebox.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_download_client_freebox.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_token"}, }, // Delete testing automatically occurs in TestCase }, diff --git a/internal/provider/download_client_hadouken_resource_test.go b/internal/provider/download_client_hadouken_resource_test.go index 6dac26a2..2a60cae1 100644 --- a/internal/provider/download_client_hadouken_resource_test.go +++ b/internal/provider/download_client_hadouken_resource_test.go @@ -43,9 +43,10 @@ func TestAccDownloadClientHadoukenResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_download_client_hadouken.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_download_client_hadouken.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"password"}, }, // Delete testing automatically occurs in TestCase }, diff --git a/internal/provider/download_client_nzbvortex_resource.go b/internal/provider/download_client_nzbvortex_resource.go index cdc3133c..adb57b1f 100644 --- a/internal/provider/download_client_nzbvortex_resource.go +++ b/internal/provider/download_client_nzbvortex_resource.go @@ -174,6 +174,7 @@ func (r *DownloadClientNzbvortexResource) Schema(_ context.Context, _ resource.S "api_key": schema.StringAttribute{ MarkdownDescription: "API key.", Required: true, + Sensitive: true, }, }, } diff --git a/internal/provider/download_client_nzbvortex_resource_test.go b/internal/provider/download_client_nzbvortex_resource_test.go index 5f6545ef..42130d67 100644 --- a/internal/provider/download_client_nzbvortex_resource_test.go +++ b/internal/provider/download_client_nzbvortex_resource_test.go @@ -43,9 +43,10 @@ func TestAccDownloadClientNzbvortexResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_download_client_nzbvortex.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_download_client_nzbvortex.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, }, // Delete testing automatically occurs in TestCase }, diff --git a/internal/provider/download_client_resource.go b/internal/provider/download_client_resource.go index 2e07f51a..9cf274e0 100644 --- a/internal/provider/download_client_resource.go +++ b/internal/provider/download_client_resource.go @@ -314,6 +314,7 @@ func (r *DownloadClientResource) Schema(_ context.Context, _ resource.SchemaRequ MarkdownDescription: "API key.", Optional: true, Computed: true, + Sensitive: true, }, "rpc_path": schema.StringAttribute{ MarkdownDescription: "RPC path.", @@ -345,6 +346,7 @@ func (r *DownloadClientResource) Schema(_ context.Context, _ resource.SchemaRequ MarkdownDescription: "Secret token.", Optional: true, Computed: true, + Sensitive: true, }, "username": schema.StringAttribute{ MarkdownDescription: "Username.", @@ -465,13 +467,14 @@ func (r *DownloadClientResource) Create(ctx context.Context, req resource.Create // this is needed because of many empty fields are unknown in both plan and read var state DownloadClient + state.writeSensitive(client) state.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } func (r *DownloadClientResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // Get current state - var client DownloadClient + var client *DownloadClient resp.Diagnostics.Append(req.State.Get(ctx, &client)...) @@ -492,6 +495,7 @@ func (r *DownloadClientResource) Read(ctx context.Context, req resource.ReadRequ // this is needed because of many empty fields are unknown in both plan and read var state DownloadClient + state.writeSensitive(client) state.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } @@ -521,6 +525,7 @@ func (r *DownloadClientResource) Update(ctx context.Context, req resource.Update // this is needed because of many empty fields are unknown in both plan and read var state DownloadClient + state.writeSensitive(client) state.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } @@ -588,3 +593,22 @@ func (d *DownloadClient) read(ctx context.Context, diags *diag.Diagnostics) *rad return client } + +// writeSensitive copy sensitive data from another resource. +func (d *DownloadClient) writeSensitive(client *DownloadClient) { + if !client.Password.IsUnknown() { + d.Password = client.Password + } + + if !client.APIKey.IsUnknown() { + d.APIKey = client.APIKey + } + + if !client.SecretToken.IsUnknown() { + d.SecretToken = client.SecretToken + } + + if !client.AppToken.IsUnknown() { + d.AppToken = client.AppToken + } +} diff --git a/internal/provider/download_client_resource_test.go b/internal/provider/download_client_resource_test.go index 802cf827..84846378 100644 --- a/internal/provider/download_client_resource_test.go +++ b/internal/provider/download_client_resource_test.go @@ -47,6 +47,12 @@ func TestAccDownloadClientResource(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + ResourceName: "radarr_download_client.test_sensitive", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"password"}, + }, // Delete testing automatically occurs in TestCase }, }) @@ -64,5 +70,20 @@ func testAccDownloadClientResourceConfig(name, enable string) string { host = "transmission" url_base = "/transmission/" port = 9091 - }`, enable, name) + } + + resource "radarr_download_client" "test_sensitive" { + enable = false + priority = 1 + name = "%sWithSensitive" + host = "hadouken" + url_base = "/hadouken/" + port = 9091 + category = "sonarr-tv" + username = "username" + password = "password" + protocol = "torrent" + config_contract = "HadoukenSettings" + implementation = "Hadouken" + }`, enable, name, name) } diff --git a/internal/provider/download_client_sabnzbd_resource_test.go b/internal/provider/download_client_sabnzbd_resource_test.go index 9a6e2786..2d063f6f 100644 --- a/internal/provider/download_client_sabnzbd_resource_test.go +++ b/internal/provider/download_client_sabnzbd_resource_test.go @@ -43,9 +43,10 @@ func TestAccDownloadClientSabnzbdResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_download_client_sabnzbd.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_download_client_sabnzbd.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, }, // Delete testing automatically occurs in TestCase }, diff --git a/internal/provider/import_list_couch_potato_resource_test.go b/internal/provider/import_list_couch_potato_resource_test.go index 8f20256c..2f5af01b 100644 --- a/internal/provider/import_list_couch_potato_resource_test.go +++ b/internal/provider/import_list_couch_potato_resource_test.go @@ -43,9 +43,10 @@ func TestAccImportListCouchPotatoResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_import_list_couch_potato.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_import_list_couch_potato.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, }, // Delete testing automatically occurs in TestCase }, diff --git a/internal/provider/import_list_radarr_resource_test.go b/internal/provider/import_list_radarr_resource_test.go index 021750d7..af12091a 100644 --- a/internal/provider/import_list_radarr_resource_test.go +++ b/internal/provider/import_list_radarr_resource_test.go @@ -43,9 +43,10 @@ func TestAccImportListRadarrResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_import_list_radarr.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_import_list_radarr.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, }, // Delete testing automatically occurs in TestCase }, diff --git a/internal/provider/import_list_resource.go b/internal/provider/import_list_resource.go index 26cae8df..41695c24 100644 --- a/internal/provider/import_list_resource.go +++ b/internal/provider/import_list_resource.go @@ -501,6 +501,7 @@ func (r *ImportListResource) Create(ctx context.Context, req resource.CreateRequ // this is needed because of many empty fields are unknown in both plan and read var state ImportList + state.writeSensitive(importList) state.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } @@ -528,6 +529,7 @@ func (r *ImportListResource) Read(ctx context.Context, req resource.ReadRequest, // this is needed because of many empty fields are unknown in both plan and read var state ImportList + state.writeSensitive(importList) state.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } @@ -557,6 +559,7 @@ func (r *ImportListResource) Update(ctx context.Context, req resource.UpdateRequ // this is needed because of many empty fields are unknown in both plan and read var state ImportList + state.writeSensitive(importList) state.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } @@ -631,3 +634,10 @@ func (i *ImportList) read(ctx context.Context, diags *diag.Diagnostics) *radarr. return list } + +// writeSensitive copy sensitive data from another resource. +func (i *ImportList) writeSensitive(importList *ImportList) { + if !importList.APIKey.IsUnknown() { + i.APIKey = importList.APIKey + } +} diff --git a/internal/provider/import_list_resource_test.go b/internal/provider/import_list_resource_test.go index 73f3b7a8..e014811d 100644 --- a/internal/provider/import_list_resource_test.go +++ b/internal/provider/import_list_resource_test.go @@ -43,9 +43,10 @@ func TestAccImportListResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_import_list.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_import_list.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, }, // Delete testing automatically occurs in TestCase }, diff --git a/internal/provider/indexer_filelist_resource_test.go b/internal/provider/indexer_filelist_resource_test.go index 4ae4953b..51b95459 100644 --- a/internal/provider/indexer_filelist_resource_test.go +++ b/internal/provider/indexer_filelist_resource_test.go @@ -42,9 +42,10 @@ func TestAccIndexerFilelistResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_indexer_filelist.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_indexer_filelist.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"passkey"}, }, // Delete testing automatically occurs in TestCase }, diff --git a/internal/provider/indexer_hdbits_resource_test.go b/internal/provider/indexer_hdbits_resource_test.go index 5e32f31d..454fcbed 100644 --- a/internal/provider/indexer_hdbits_resource_test.go +++ b/internal/provider/indexer_hdbits_resource_test.go @@ -42,9 +42,10 @@ func TestAccIndexerHdbitsResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_indexer_hdbits.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_indexer_hdbits.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, }, // Delete testing automatically occurs in TestCase }, diff --git a/internal/provider/indexer_newznab_resource.go b/internal/provider/indexer_newznab_resource.go index f40a6f3c..dca4dfc8 100644 --- a/internal/provider/indexer_newznab_resource.go +++ b/internal/provider/indexer_newznab_resource.go @@ -163,6 +163,7 @@ func (r *IndexerNewznabResource) Schema(_ context.Context, _ resource.SchemaRequ MarkdownDescription: "API key.", Optional: true, Computed: true, + Sensitive: true, }, "api_path": schema.StringAttribute{ MarkdownDescription: "API path.", diff --git a/internal/provider/indexer_resource.go b/internal/provider/indexer_resource.go index fb789283..aa9947a2 100644 --- a/internal/provider/indexer_resource.go +++ b/internal/provider/indexer_resource.go @@ -232,6 +232,7 @@ func (r *IndexerResource) Schema(_ context.Context, _ resource.SchemaRequest, re MarkdownDescription: "API key.", Optional: true, Computed: true, + Sensitive: true, }, "api_user": schema.StringAttribute{ MarkdownDescription: "API User.", @@ -262,6 +263,7 @@ func (r *IndexerResource) Schema(_ context.Context, _ resource.SchemaRequest, re MarkdownDescription: "Passkey.", Optional: true, Computed: true, + Sensitive: true, }, "username": schema.StringAttribute{ MarkdownDescription: "Username.", @@ -338,6 +340,7 @@ func (r *IndexerResource) Create(ctx context.Context, req resource.CreateRequest // this is needed because of many empty fields are unknown in both plan and read var state Indexer + state.writeSensitive(indexer) state.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } @@ -365,6 +368,7 @@ func (r *IndexerResource) Read(ctx context.Context, req resource.ReadRequest, re // this is needed because of many empty fields are unknown in both plan and read var state Indexer + state.writeSensitive(indexer) state.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } @@ -394,6 +398,7 @@ func (r *IndexerResource) Update(ctx context.Context, req resource.UpdateRequest // this is needed because of many empty fields are unknown in both plan and read var state Indexer + state.writeSensitive(indexer) state.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } @@ -465,3 +470,14 @@ func (i *Indexer) read(ctx context.Context, diags *diag.Diagnostics) *radarr.Ind return indexer } + +// writeSensitive copy sensitive data from another resource. +func (i *Indexer) writeSensitive(indexer *Indexer) { + if !indexer.Passkey.IsUnknown() { + i.Passkey = indexer.Passkey + } + + if !indexer.APIKey.IsUnknown() { + i.APIKey = indexer.APIKey + } +} diff --git a/internal/provider/indexer_resource_test.go b/internal/provider/indexer_resource_test.go index d1b0a15f..4de96278 100644 --- a/internal/provider/indexer_resource_test.go +++ b/internal/provider/indexer_resource_test.go @@ -47,6 +47,12 @@ func TestAccIndexerResource(t *testing.T) { ImportState: true, ImportStateVerify: true, }, + { + ResourceName: "radarr_indexer.test_sensitive", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"passkey"}, + }, // Delete testing automatically occurs in TestCase }, }) @@ -63,5 +69,19 @@ func testAccIndexerResourceConfig(name, aSearch string) string { base_url = "https://lolo.sickbeard.com" api_path = "/api" categories = [8000, 5000] - }`, aSearch, name) + } + + resource "radarr_indexer" "test_sensitive" { + enable_automatic_search = false + name = "%sWithSensitive" + base_url = "https://filelist.io" + username = "test" + passkey = "Pass" + categories = [21,23,27] + minimum_seeders = 1 + implementation = "FileList" + protocol = "torrent" + config_contract = "FileListSettings" + } + `, aSearch, name, name) } diff --git a/internal/provider/indexer_torrent_potato_resource_test.go b/internal/provider/indexer_torrent_potato_resource_test.go index 269b7437..796b8fde 100644 --- a/internal/provider/indexer_torrent_potato_resource_test.go +++ b/internal/provider/indexer_torrent_potato_resource_test.go @@ -42,9 +42,10 @@ func TestAccIndexerTorrentPotatoResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_indexer_torrent_potato.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_indexer_torrent_potato.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"passkey"}, }, // Delete testing automatically occurs in TestCase }, diff --git a/internal/provider/notification_boxcar_resource_test.go b/internal/provider/notification_boxcar_resource_test.go index 400330ec..3a5b5885 100644 --- a/internal/provider/notification_boxcar_resource_test.go +++ b/internal/provider/notification_boxcar_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationBoxcarResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_boxcar.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_boxcar.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"token"}, }, // Delete testing automatically occurs in TestCase }, @@ -63,10 +64,10 @@ func testAccNotificationBoxcarResourceConfig(name, token string) string { on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" - + token = "%s" }`, name, token) } diff --git a/internal/provider/notification_emby_resource_test.go b/internal/provider/notification_emby_resource_test.go index f0a81109..39362161 100644 --- a/internal/provider/notification_emby_resource_test.go +++ b/internal/provider/notification_emby_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationEmbyResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_emby.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_emby.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, }, // Delete testing automatically occurs in TestCase }, @@ -64,10 +65,10 @@ func testAccNotificationEmbyResourceConfig(name, token string) string { on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" - + host = "emby.lcl" port = 8096 api_key = "%s" diff --git a/internal/provider/notification_gotify_resource_test.go b/internal/provider/notification_gotify_resource_test.go index c86eb87c..e3e8799d 100644 --- a/internal/provider/notification_gotify_resource_test.go +++ b/internal/provider/notification_gotify_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationGotifyResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_gotify.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_gotify.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_token"}, }, // Delete testing automatically occurs in TestCase }, @@ -63,10 +64,10 @@ func testAccNotificationGotifyResourceConfig(name string, priority int) string { on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" - + server = "http://gotify-server.net" app_token = "Token" priority = %d diff --git a/internal/provider/notification_join_resource_test.go b/internal/provider/notification_join_resource_test.go index 2a9e8bcf..a24b3855 100644 --- a/internal/provider/notification_join_resource_test.go +++ b/internal/provider/notification_join_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationJoinResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_join.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_join.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, }, // Delete testing automatically occurs in TestCase }, @@ -63,10 +64,10 @@ func testAccNotificationJoinResourceConfig(name string, priority int) string { on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" - + device_names = "test,test1" api_key = "Key" priority = %d diff --git a/internal/provider/notification_kodi_resource_test.go b/internal/provider/notification_kodi_resource_test.go index e0c602ef..60c0f9d7 100644 --- a/internal/provider/notification_kodi_resource_test.go +++ b/internal/provider/notification_kodi_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationKodiResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_kodi.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_kodi.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"password"}, }, // Delete testing automatically occurs in TestCase }, @@ -64,10 +65,10 @@ func testAccNotificationKodiResourceConfig(name, avatar string) string { on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" - + host = "http://kodi.com" port = 8080 username = "User" diff --git a/internal/provider/notification_notifiarr_resource_test.go b/internal/provider/notification_notifiarr_resource_test.go index 2120d14d..e03087b6 100644 --- a/internal/provider/notification_notifiarr_resource_test.go +++ b/internal/provider/notification_notifiarr_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationNotifiarrResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_notifiarr.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_notifiarr.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, }, // Delete testing automatically occurs in TestCase }, @@ -63,10 +64,10 @@ func testAccNotificationNotifiarrResourceConfig(name, key string) string { on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" - + api_key = "%s" }`, name, key) } diff --git a/internal/provider/notification_ntfy_resource_test.go b/internal/provider/notification_ntfy_resource_test.go index 9b49e2e3..a1c48197 100644 --- a/internal/provider/notification_ntfy_resource_test.go +++ b/internal/provider/notification_ntfy_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationNtfyResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_ntfy.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_ntfy.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"password"}, }, // Delete testing automatically occurs in TestCase }, @@ -63,7 +64,7 @@ func testAccNotificationNtfyResourceConfig(name, key string) string { on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" diff --git a/internal/provider/notification_plex_resource_test.go b/internal/provider/notification_plex_resource_test.go index 5be0c945..6a0700ca 100644 --- a/internal/provider/notification_plex_resource_test.go +++ b/internal/provider/notification_plex_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationPlexResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_plex.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_plex.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"auth_token"}, }, // Delete testing automatically occurs in TestCase }, @@ -61,10 +62,10 @@ func testAccNotificationPlexResourceConfig(name, token string) string { on_movie_delete = false on_movie_file_delete = false on_movie_file_delete_for_upgrade = false - + include_health_warnings = false name = "%s" - + host = "plex.lcl" port = 32400 auth_token = "%s" diff --git a/internal/provider/notification_prowl_resource_test.go b/internal/provider/notification_prowl_resource_test.go index 37f7df9b..00efb4ff 100644 --- a/internal/provider/notification_prowl_resource_test.go +++ b/internal/provider/notification_prowl_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationProwlResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_prowl.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_prowl.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, }, // Delete testing automatically occurs in TestCase }, @@ -63,10 +64,10 @@ func testAccNotificationProwlResourceConfig(name string, priority int) string { on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" - + api_key = "Key" priority = %d }`, name, priority) diff --git a/internal/provider/notification_pushbullet_resource_test.go b/internal/provider/notification_pushbullet_resource_test.go index ee50ebeb..001e3139 100644 --- a/internal/provider/notification_pushbullet_resource_test.go +++ b/internal/provider/notification_pushbullet_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationPushbulletResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_pushbullet.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_pushbullet.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, }, // Delete testing automatically occurs in TestCase }, @@ -63,10 +64,10 @@ func testAccNotificationPushbulletResourceConfig(name, key string) string { on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" - + api_key = "%s" device_ids = ["test"] }`, name, key) diff --git a/internal/provider/notification_pushover_resource_test.go b/internal/provider/notification_pushover_resource_test.go index a106ecb0..5a5d286d 100644 --- a/internal/provider/notification_pushover_resource_test.go +++ b/internal/provider/notification_pushover_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationPushoverResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_pushover.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_pushover.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, }, // Delete testing automatically occurs in TestCase }, @@ -63,10 +64,10 @@ func testAccNotificationPushoverResourceConfig(name string, priority int) string on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" - + api_key = "Key" user_key = "Test" priority = %d diff --git a/internal/provider/notification_resource.go b/internal/provider/notification_resource.go index 4ecfb081..5306e6d0 100644 --- a/internal/provider/notification_resource.go +++ b/internal/provider/notification_resource.go @@ -34,6 +34,7 @@ var notificationFields = helpers.Fields{ StringSlices: []string{"recipients", "to", "cC", "bcc", "topics", "deviceIds", "fieldTags", "channelTags", "devices"}, StringSlicesExceptions: []string{"tags"}, IntSlices: []string{"grabFields", "importFields"}, + // Sensitive: []string{"apiKey", "token", "password", "appToken", "authToken", "botToken", "accessToken", "accessTokenSecret", "consumerKey", "consumerSecret", "configurationKey", "authPassword"}, } func NewNotificationResource() resource.Resource { @@ -436,11 +437,13 @@ func (r *NotificationResource) Schema(_ context.Context, _ resource.SchemaReques MarkdownDescription: "API key.", Optional: true, Computed: true, + Sensitive: true, }, "app_token": schema.StringAttribute{ MarkdownDescription: "App token.", Optional: true, Computed: true, + Sensitive: true, }, "arguments": schema.StringAttribute{ MarkdownDescription: "Arguments.", @@ -501,6 +504,7 @@ func (r *NotificationResource) Schema(_ context.Context, _ resource.SchemaReques MarkdownDescription: "Consumer secret.", Optional: true, Computed: true, + Sensitive: true, }, "device_names": schema.StringAttribute{ MarkdownDescription: "Device names.", @@ -751,6 +755,7 @@ func (r *NotificationResource) Create(ctx context.Context, req resource.CreateRe // this is needed because of many empty fields are unknown in both plan and read var state Notification + state.writeSensitive(notification) state.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } @@ -778,6 +783,7 @@ func (r *NotificationResource) Read(ctx context.Context, req resource.ReadReques // this is needed because of many empty fields are unknown in both plan and read var state Notification + state.writeSensitive(notification) state.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } @@ -807,6 +813,7 @@ func (r *NotificationResource) Update(ctx context.Context, req resource.UpdateRe // this is needed because of many empty fields are unknown in both plan and read var state Notification + state.writeSensitive(notification) state.write(ctx, response, &resp.Diagnostics) resp.Diagnostics.Append(resp.State.Set(ctx, state)...) } @@ -898,3 +905,50 @@ func (n *Notification) read(ctx context.Context, diags *diag.Diagnostics) *radar return notification } + +// writeSensitive copy sensitive data from another resource. +func (n *Notification) writeSensitive(notification *Notification) { + if !notification.Token.IsUnknown() { + n.Token = notification.Token + } + + if !notification.APIKey.IsUnknown() { + n.APIKey = notification.APIKey + } + + if !notification.Password.IsUnknown() { + n.Password = notification.Password + } + + if !notification.AppToken.IsUnknown() { + n.AppToken = notification.AppToken + } + + if !notification.BotToken.IsUnknown() { + n.BotToken = notification.BotToken + } + + if !notification.AccessToken.IsUnknown() { + n.AccessToken = notification.AccessToken + } + + if !notification.AccessTokenSecret.IsUnknown() { + n.AccessTokenSecret = notification.AccessTokenSecret + } + + if !notification.ConsumerKey.IsUnknown() { + n.ConsumerKey = notification.ConsumerKey + } + + if !notification.ConsumerSecret.IsUnknown() { + n.ConsumerSecret = notification.ConsumerSecret + } + + if !notification.ConfigurationKey.IsUnknown() { + n.ConfigurationKey = notification.ConfigurationKey + } + + if !notification.AuthPassword.IsUnknown() { + n.AuthPassword = notification.AuthPassword + } +} diff --git a/internal/provider/notification_sendgrid_resource_test.go b/internal/provider/notification_sendgrid_resource_test.go index 5f266b46..f35f4f96 100644 --- a/internal/provider/notification_sendgrid_resource_test.go +++ b/internal/provider/notification_sendgrid_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationSendgridResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_sendgrid.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_sendgrid.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"api_key"}, }, // Delete testing automatically occurs in TestCase }, @@ -63,10 +64,10 @@ func testAccNotificationSendgridResourceConfig(name, from string) string { on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" - + api_key = "APIkey" from = "%s" recipients = ["test@test.com", "test1@test.com"] diff --git a/internal/provider/notification_simplepush_resource_test.go b/internal/provider/notification_simplepush_resource_test.go index 651ac764..cf0b59c9 100644 --- a/internal/provider/notification_simplepush_resource_test.go +++ b/internal/provider/notification_simplepush_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationSimplepushResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_simplepush.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_simplepush.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"key"}, }, // Delete testing automatically occurs in TestCase }, @@ -63,10 +64,10 @@ func testAccNotificationSimplepushResourceConfig(name, key string) string { on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" - + key = "%s" event = "ringtone:default" }`, name, key) diff --git a/internal/provider/notification_telegram_resource_test.go b/internal/provider/notification_telegram_resource_test.go index 617b7f32..caf0a6d6 100644 --- a/internal/provider/notification_telegram_resource_test.go +++ b/internal/provider/notification_telegram_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationTelegramResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_telegram.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_telegram.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"bot_token"}, }, // Delete testing automatically occurs in TestCase }, @@ -63,10 +64,10 @@ func testAccNotificationTelegramResourceConfig(name, chat string) string { on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" - + chat_id = "%s" bot_token = "Token" }`, name, chat) diff --git a/internal/provider/notification_twitter_resource_test.go b/internal/provider/notification_twitter_resource_test.go index bcc931be..372da762 100644 --- a/internal/provider/notification_twitter_resource_test.go +++ b/internal/provider/notification_twitter_resource_test.go @@ -42,9 +42,10 @@ func TestAccNotificationTwitterResource(t *testing.T) { }, // ImportState testing { - ResourceName: "radarr_notification_twitter.test", - ImportState: true, - ImportStateVerify: true, + ResourceName: "radarr_notification_twitter.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"access_token", "consumer_key", "consumer_secret"}, }, // Delete testing automatically occurs in TestCase }, @@ -63,10 +64,10 @@ func testAccNotificationTwitterResourceConfig(name, mention string) string { on_movie_file_delete_for_upgrade = false on_health_issue = false on_application_update = false - + include_health_warnings = false name = "%s" - + access_token = "Token" access_token_secret = "TokenSecret" consumer_key = "Key"