diff --git a/docs/resources/question.md b/docs/resources/question.md index 301910f4..141ded9d 100644 --- a/docs/resources/question.md +++ b/docs/resources/question.md @@ -39,6 +39,7 @@ resource "jupiterone_question" "unencrypted_critical_data_stores" { - `compliance` (Block List) (see [below for nested schema](#nestedblock--compliance)) - `polling_interval` (String) Frequency of automated question evaluation. Defaults to ONE_DAY. - `query` (Block List) (see [below for nested schema](#nestedblock--query)) +- `show_trend` (Boolean) Whether to enable trend data collection. Defaults to false. - `tags` (List of String) ### Read-Only diff --git a/jupiterone/cassettes/TestQuestion_Config_Errors.yaml b/jupiterone/cassettes/TestQuestion_Config_Errors.yaml new file mode 100644 index 00000000..2797c38e --- /dev/null +++ b/jupiterone/cassettes/TestQuestion_Config_Errors.yaml @@ -0,0 +1,3 @@ +--- +version: 2 +interactions: [] diff --git a/jupiterone/internal/client/question.graphql b/jupiterone/internal/client/question.graphql index ef51ab6a..c491c6cf 100644 --- a/jupiterone/internal/client/question.graphql +++ b/jupiterone/internal/client/question.graphql @@ -3,6 +3,7 @@ query GetQuestionById($id: ID!) { id title description + showTrend pollingInterval # @genqlient(typename: QuestionQuery) queries { diff --git a/jupiterone/resource_question.go b/jupiterone/resource_question.go index cce17b68..c787de8b 100644 --- a/jupiterone/resource_question.go +++ b/jupiterone/resource_question.go @@ -64,6 +64,7 @@ type QuestionModel struct { Id types.String `json:"id,omitempty" tfsdk:"id"` Title types.String `json:"title,omitempty" tfsdk:"title"` Description types.String `json:"description,omitempty" tfsdk:"description"` + ShowTrend types.Bool `json:"show_trend,omitempty" tfsdk:"show_trend"` PollingInterval types.String `json:"polling_interval,omitempty" tfsdk:"polling_interval"` Tags []string `json:"tags,omitempty" tfsdk:"tags"` Query []*QuestionQueryModel `json:"query,omitempty" tfsdk:"query"` @@ -97,6 +98,14 @@ func (*QuestionResource) Schema(ctx context.Context, req resource.SchemaRequest, "description": schema.StringAttribute{ Required: true, }, + "show_trend": schema.BoolAttribute{ + Description: "Whether to enable daily trend data collection. Defaults to false.", + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.Bool{ + BoolDefaultValuePlanModifier(false), + }, + }, "polling_interval": schema.StringAttribute{ Description: "Frequency of automated question evaluation. Defaults to ONE_DAY.", Computed: true, @@ -328,6 +337,7 @@ func (qm *QuestionModel) BuildQuestion() client.QuestionUpdate { Title: qm.Title.ValueString(), Description: qm.Description.ValueString(), Tags: qm.Tags, + ShowTrend: qm.ShowTrend.ValueBool(), PollingInterval: client.SchedulerPollingInterval(qm.PollingInterval.ValueString()), } @@ -359,6 +369,7 @@ func (qm *QuestionModel) BuildCreateQuestionInput() client.CreateQuestionInput { Title: qm.Title.ValueString(), Description: qm.Description.ValueString(), PollingInterval: client.SchedulerPollingInterval(qm.PollingInterval.ValueString()), + ShowTrend: qm.ShowTrend.ValueBool(), Tags: qm.Tags, } diff --git a/jupiterone/resource_question_test.go b/jupiterone/resource_question_test.go index 6419c6cd..c8c63bf4 100644 --- a/jupiterone/resource_question_test.go +++ b/jupiterone/resource_question_test.go @@ -3,11 +3,13 @@ package jupiterone import ( "context" "fmt" + "regexp" "strings" "testing" "time" "github.com/Khan/genqlient/graphql" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/jupiterone/terraform-provider-jupiterone/jupiterone/internal/client" @@ -33,6 +35,7 @@ func TestQuestion_Basic(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "id"), resource.TestCheckResourceAttr(resourceName, "title", questionTitle), resource.TestCheckResourceAttr(resourceName, "description", "Test"), + resource.TestCheckResourceAttr(resourceName, "show_trend", "false"), resource.TestCheckResourceAttr(resourceName, "tags.#", "1"), resource.TestCheckResourceAttr(resourceName, "tags.0", "tf_acc:1"), resource.TestCheckResourceAttr(resourceName, "query.#", "1"), @@ -48,6 +51,7 @@ func TestQuestion_Basic(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "id"), resource.TestCheckResourceAttr(resourceName, "title", questionTitle), resource.TestCheckResourceAttr(resourceName, "description", "Test"), + resource.TestCheckResourceAttr(resourceName, "show_trend", "false"), resource.TestCheckResourceAttr(resourceName, "tags.#", "1"), resource.TestCheckResourceAttr(resourceName, "tags.0", "tf_acc:2"), resource.TestCheckResourceAttr(resourceName, "query.#", "1"), @@ -84,6 +88,7 @@ func TestQuestion_BasicImport(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "id"), resource.TestCheckResourceAttr(resourceName, "title", questionTitle), resource.TestCheckResourceAttr(resourceName, "description", "Test"), + resource.TestCheckResourceAttr(resourceName, "show_trend", "false"), resource.TestCheckResourceAttr(resourceName, "tags.#", "1"), resource.TestCheckResourceAttr(resourceName, "tags.0", "tf_acc:1"), resource.TestCheckResourceAttr(resourceName, "query.#", "1"), @@ -96,6 +101,25 @@ func TestQuestion_BasicImport(t *testing.T) { }) } +func TestQuestion_Config_Errors(t *testing.T) { + ctx := context.TODO() + + recordingClient, _, cleanup := setupTestClients(ctx, t) + defer cleanup(t) + + questionTitle := acctest.RandomWithPrefix("tf-provider-test-question") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(recordingClient), + Steps: []resource.TestStep{ + { + Config: testQuestionBasicConfigWithShowTrend(questionTitle, "INVALID_SHOW_TREND"), + ExpectError: regexp.MustCompile(`Inappropriate value for attribute "show_trend"`), + }, + }, + }) +} + // createTestQuestion directly calls the client to create a question directly // for import or other tests. Because the id must be returned, this must // called with the recorder client. @@ -199,6 +223,24 @@ func questionDestroyHelper(ctx context.Context, s *terraform.State, qlient graph return nil } +func testQuestionBasicConfigWithShowTrend(rName string, showTrend string) string { + return fmt.Sprintf(` + provider "jupiterone" {} + + resource "jupiterone_question" "test" { + title = %q + description = "Test" + show_trend = %q + + query { + name = "query0" + query = "Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true" + version = "v1" + } + } + `, rName, showTrend) +} + func testQuestionBasicConfigWithTags(rName string, tag string) string { return fmt.Sprintf(` provider "jupiterone" {}