diff --git a/README.md b/README.md index 7d7df33e..618c32fa 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,8 @@ This function is used to create the actual resource. It parses out the J1EntityM Follow this general structure for your create function and look at other resource.go files to get an idea of what you may need here. +Note that if the resource you are creating does not return an `id` from the API, you will need to assign a unique id to the `data.Id` field. This is used by terraform to track the resource. The `user_group_membership` resource is one where this is necessary and can be used as an example. + ```go func (r *J1EntityResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data J1EntityModel diff --git a/docs/resources/resource_permission.md b/docs/resources/resource_permission.md new file mode 100644 index 00000000..65894ae3 --- /dev/null +++ b/docs/resources/resource_permission.md @@ -0,0 +1,47 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "jupiterone_resource_permission Resource - terraform-provider-jupiterone" +subcategory: "" +description: |- + A set of resource based permissions. +--- + +# jupiterone_resource_permission (Resource) + +A set of JupiterOne Resource Permissions. + +## Example Usage + +```terraform +data "jupiterone_user_group" "standard_administrators" { + name = "Administrators" +} + +resource "jupiterone_resource_permission" "administrator_permissions" { + subject_id = data.jupiterone_user_group.standard_administrators.id + subject_type = "group" + resource_area = "rule" + resource_type = "*" + resource_id = "*" + can_create = true + can_read = true + can_update = true + can_delete = true +} +``` + + + +## Schema + +### Required + +- `subject_id` (String) The ID of the subject that the resource permissions will be applied to (e.g. group ID). +- `subject_type` (String) The type of the subject that the resource permissions will be applied to (e.g. group). +- `resource_area` (String) The resource area that these permissions will be applied to (e.g. rule). +- `resource_type` (String) The resource type that these permissions will be applied to (e.g. rule, rule_collection, \*). +- `resource_id` (String) The resource ID that these permissions will be applied to (e.g. rule ID, rule_collection ID, \*). +- `can_read` (Boolean) Whether the subject can read the resource. +- `can_create` (Boolean) Whether the subject can create the resource. +- `can_update` (Boolean) Whether the subject can update the resource. +- `can_delete` (Boolean) Whether the subject can delete the resource. diff --git a/docs/resources/rule.md b/docs/resources/rule.md index 12e75d94..cc1ea7ed 100644 --- a/docs/resources/rule.md +++ b/docs/resources/rule.md @@ -126,6 +126,7 @@ resource "jupiterone_rule" "users_without_mfa" { - `labels` (List of Attributes) Key/value pairs to apply to the jupiterone_rule entity. If label_value is a string that represents a boolean or number (i.e. "true", "1"), it will be converted to a boolean or number respectively. - `templates` (Map of String) Optional key/value pairs of template name to template - `trigger_on_new_only` (Boolean) +- `collection_id` (String) Optional ID of a collection to associate with the rule. ### Read-Only diff --git a/jupiterone/cassettes/TestInlineRuleInstance_Basic.yaml b/jupiterone/cassettes/TestInlineRuleInstance_Basic.yaml index 37b042a8..3b520269 100644 --- a/jupiterone/cassettes/TestInlineRuleInstance_Basic.yaml +++ b/jupiterone/cassettes/TestInlineRuleInstance_Basic.yaml @@ -6,20 +6,20 @@ interactions: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 1329 + content_length: 1311 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nmutation CreateInlineQuestionRuleInstance ($instance: CreateInlineQuestionRuleInstanceInput!) {\n\tcreateQuestionRuleInstance: createInlineQuestionRuleInstance(instance: $instance) {\n\t\tid\n\t\tversion\n\t\tspecVersion\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\tlabels {\n\t\t\tlabelName\n\t\t\tlabelValue\n\t\t}\n\t}\n}\n","variables":{"instance":{"question":{"queries":[{"query":"Find DataStore with classification=(''critical'' or ''sensitive'' or ''confidential'' or ''restricted'') and encrypted!=true","name":"query0","version":"v1","includeDeleted":false}]},"templates":null,"tags":["tf_acc:1","tf_acc:2"],"name":"tf-provider-test-rule","description":"Test","specVersion":1,"operations":[{"when":{"condition":"{{queries.query0.total != 0}}","specVersion":1,"type":"FILTER"},"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY"},{"type":"CREATE_ALERT"}]}],"outputs":["queries.query0.total","alertLevel"],"pollingInterval":"ONE_WEEK","notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":true,"ignorePreviousResults":false,"remediationSteps":"","collectionId":"","labels":null,"j1Internal":false}},"operationName":"CreateInlineQuestionRuleInstance"}' + body: '{"query":"\nmutation CreateInlineQuestionRuleInstance ($instance: CreateInlineQuestionRuleInstanceInput!) {\n\tcreateQuestionRuleInstance: createInlineQuestionRuleInstance(instance: $instance) {\n\t\tid\n\t\tversion\n\t\tspecVersion\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\tlabels {\n\t\t\tlabelName\n\t\t\tlabelValue\n\t\t}\n\t}\n}\n","variables":{"instance":{"question":{"queries":[{"query":"Find DataStore with classification=(''critical'' or ''sensitive'' or ''confidential'' or ''restricted'') and encrypted!=true","name":"query0","version":"v1","includeDeleted":false}]},"templates":null,"tags":["tf_acc:1","tf_acc:2"],"name":"tf-provider-test-rule","description":"Test","specVersion":1,"operations":[{"when":{"condition":"{{queries.query0.total != 0}}","specVersion":1,"type":"FILTER"},"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY"},{"type":"CREATE_ALERT"}]}],"outputs":["queries.query0.total","alertLevel"],"pollingInterval":"ONE_WEEK","notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":true,"ignorePreviousResults":false,"remediationSteps":"","labels":null,"j1Internal":false}},"operationName":"CreateInlineQuestionRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -30,7 +30,7 @@ interactions: content_length: 635 uncompressed: false body: | - {"data":{"createQuestionRuleInstance":{"id":"d4ebcdb5-7bea-4e4e-9fd7-fd0b677ea2cc","version":1,"specVersion":1,"question":{"queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false}]},"operations":[{"when":{"condition":"{{queries.query0.total != 0}}","specVersion":1,"type":"FILTER"},"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY","id":"c441b02c-32f3-4059-8786-2ab7de31924e"},{"type":"CREATE_ALERT","id":"468fa7af-c92f-47b5-a795-fe6d44af0d55"}]}],"labels":[]}}} + {"data":{"createQuestionRuleInstance":{"id":"d3052389-8599-439e-a9e8-f1827ef4eacc","version":1,"specVersion":1,"question":{"queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false}]},"operations":[{"when":{"condition":"{{queries.query0.total != 0}}","specVersion":1,"type":"FILTER"},"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY","id":"321601b9-fa1b-406a-8739-3eafdd7c9cd2"},{"type":"CREATE_ALERT","id":"4091bf3c-af3d-409b-a599-c877227ed2ca"}]}],"labels":[]}}} headers: Access-Control-Allow-Credentials: - "true" @@ -78,26 +78,26 @@ interactions: - "0" status: 200 OK code: 200 - duration: 1.028570958s + duration: 1.083248209s - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 632 + content_length: 650 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"d4ebcdb5-7bea-4e4e-9fd7-fd0b677ea2cc"},"operationName":"GetQuestionRuleInstance"}' + body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tcollectionId\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"d3052389-8599-439e-a9e8-f1827ef4eacc"},"operationName":"GetQuestionRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -105,15 +105,15 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 953 + content_length: 973 uncompressed: false body: | - {"data":{"questionRuleInstance":{"id":"d4ebcdb5-7bea-4e4e-9fd7-fd0b677ea2cc","name":"tf-provider-test-rule","description":"Test","version":1,"specVersion":1,"latest":true,"pollingInterval":"ONE_WEEK","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":true,"ignorePreviousResults":false,"questionId":null,"question":{"queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false}]},"operations":[{"when":{"type":"FILTER","condition":"{{queries.query0.total != 0}}","specVersion":1},"actions":[{"targetValue":"HIGH","id":"c441b02c-32f3-4059-8786-2ab7de31924e","type":"SET_PROPERTY","targetProperty":"alertLevel"},{"type":"CREATE_ALERT","id":"468fa7af-c92f-47b5-a795-fe6d44af0d55"}]}],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} + {"data":{"questionRuleInstance":{"id":"d3052389-8599-439e-a9e8-f1827ef4eacc","name":"tf-provider-test-rule","collectionId":null,"description":"Test","version":1,"specVersion":1,"latest":true,"pollingInterval":"ONE_WEEK","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":true,"ignorePreviousResults":false,"questionId":null,"question":{"queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false}]},"operations":[{"when":{"type":"FILTER","condition":"{{queries.query0.total != 0}}","specVersion":1},"actions":[{"targetValue":"HIGH","id":"321601b9-fa1b-406a-8739-3eafdd7c9cd2","type":"SET_PROPERTY","targetProperty":"alertLevel"},{"type":"CREATE_ALERT","id":"4091bf3c-af3d-409b-a599-c877227ed2ca"}]}],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} headers: Access-Control-Allow-Credentials: - "true" Content-Length: - - "953" + - "973" Content-Security-Policy: - 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self'' https: data:;form-action ''self'';frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src ''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests' Content-Type: @@ -156,26 +156,26 @@ interactions: - "0" status: 200 OK code: 200 - duration: 194.109083ms + duration: 156.837583ms - id: 2 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 632 + content_length: 650 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"d4ebcdb5-7bea-4e4e-9fd7-fd0b677ea2cc"},"operationName":"GetQuestionRuleInstance"}' + body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tcollectionId\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"d3052389-8599-439e-a9e8-f1827ef4eacc"},"operationName":"GetQuestionRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -183,15 +183,15 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 953 + content_length: 973 uncompressed: false body: | - {"data":{"questionRuleInstance":{"id":"d4ebcdb5-7bea-4e4e-9fd7-fd0b677ea2cc","name":"tf-provider-test-rule","description":"Test","version":1,"specVersion":1,"latest":true,"pollingInterval":"ONE_WEEK","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":true,"ignorePreviousResults":false,"questionId":null,"question":{"queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false}]},"operations":[{"when":{"type":"FILTER","condition":"{{queries.query0.total != 0}}","specVersion":1},"actions":[{"targetValue":"HIGH","id":"c441b02c-32f3-4059-8786-2ab7de31924e","type":"SET_PROPERTY","targetProperty":"alertLevel"},{"type":"CREATE_ALERT","id":"468fa7af-c92f-47b5-a795-fe6d44af0d55"}]}],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} + {"data":{"questionRuleInstance":{"id":"d3052389-8599-439e-a9e8-f1827ef4eacc","name":"tf-provider-test-rule","collectionId":null,"description":"Test","version":1,"specVersion":1,"latest":true,"pollingInterval":"ONE_WEEK","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":true,"ignorePreviousResults":false,"questionId":null,"question":{"queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false}]},"operations":[{"when":{"type":"FILTER","condition":"{{queries.query0.total != 0}}","specVersion":1},"actions":[{"targetValue":"HIGH","id":"321601b9-fa1b-406a-8739-3eafdd7c9cd2","type":"SET_PROPERTY","targetProperty":"alertLevel"},{"type":"CREATE_ALERT","id":"4091bf3c-af3d-409b-a599-c877227ed2ca"}]}],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} headers: Access-Control-Allow-Credentials: - "true" Content-Length: - - "953" + - "973" Content-Security-Policy: - 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self'' https: data:;form-action ''self'';frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src ''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests' Content-Type: @@ -234,26 +234,26 @@ interactions: - "0" status: 200 OK code: 200 - duration: 187.93225ms + duration: 460.636292ms - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 1073 + content_length: 1055 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nmutation UpdateInlineQuestionRuleInstance ($instance: UpdateInlineQuestionRuleInstanceInput!) {\n\tupdateInlineQuestionRuleInstance(instance: $instance) {\n\t\tversion\n\t\tspecVersion\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t}\n}\n","variables":{"instance":{"question":{"queries":[{"query":"Find DataStore with classification=(''critical'' or ''sensitive'' or ''confidential'' or ''restricted'') and encrypted!=true","name":"query0","version":"v1","includeDeleted":false}]},"id":"d4ebcdb5-7bea-4e4e-9fd7-fd0b677ea2cc","version":1,"state":{"actions":null},"templates":null,"tags":["tf_acc:1","tf_acc:2"],"name":"tf-provider-test-rule","description":"Test","specVersion":1,"operations":[{"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY"},{"type":"CREATE_ALERT"}]}],"outputs":["queries.query0.total","alertLevel"],"pollingInterval":"ONE_WEEK","notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":true,"ignorePreviousResults":false,"collectionId":"","labels":null}},"operationName":"UpdateInlineQuestionRuleInstance"}' + body: '{"query":"\nmutation UpdateInlineQuestionRuleInstance ($instance: UpdateInlineQuestionRuleInstanceInput!) {\n\tupdateInlineQuestionRuleInstance(instance: $instance) {\n\t\tversion\n\t\tspecVersion\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t}\n}\n","variables":{"instance":{"question":{"queries":[{"query":"Find DataStore with classification=(''critical'' or ''sensitive'' or ''confidential'' or ''restricted'') and encrypted!=true","name":"query0","version":"v1","includeDeleted":false}]},"id":"d3052389-8599-439e-a9e8-f1827ef4eacc","version":1,"state":{"actions":null},"templates":null,"tags":["tf_acc:1","tf_acc:2"],"name":"tf-provider-test-rule","description":"Test","specVersion":1,"operations":[{"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY"},{"type":"CREATE_ALERT"}]}],"outputs":["queries.query0.total","alertLevel"],"pollingInterval":"ONE_WEEK","notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":true,"ignorePreviousResults":false,"labels":null}},"operationName":"UpdateInlineQuestionRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -264,7 +264,7 @@ interactions: content_length: 304 uncompressed: false body: | - {"data":{"updateInlineQuestionRuleInstance":{"version":2,"specVersion":1,"operations":[{"when":null,"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY","id":"595397fc-f7f5-4fbd-936b-1a7ad5ae88ae"},{"type":"CREATE_ALERT","id":"69e7809d-8003-44d8-9a9b-d277868e079a"}]}]}}} + {"data":{"updateInlineQuestionRuleInstance":{"version":2,"specVersion":1,"operations":[{"when":null,"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY","id":"156ae2d8-a80f-4087-9602-00b66389631a"},{"type":"CREATE_ALERT","id":"fc2aff5f-9c5e-4234-b490-2bbfef32383b"}]}]}}} headers: Access-Control-Allow-Credentials: - "true" @@ -312,26 +312,26 @@ interactions: - "0" status: 200 OK code: 200 - duration: 629.056375ms + duration: 529.386458ms - id: 4 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 632 + content_length: 650 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"d4ebcdb5-7bea-4e4e-9fd7-fd0b677ea2cc"},"operationName":"GetQuestionRuleInstance"}' + body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tcollectionId\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"d3052389-8599-439e-a9e8-f1827ef4eacc"},"operationName":"GetQuestionRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -339,15 +339,15 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 880 + content_length: 900 uncompressed: false body: | - {"data":{"questionRuleInstance":{"id":"d4ebcdb5-7bea-4e4e-9fd7-fd0b677ea2cc","name":"tf-provider-test-rule","description":"Test","version":2,"specVersion":1,"latest":true,"pollingInterval":"ONE_WEEK","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":true,"ignorePreviousResults":false,"questionId":null,"question":{"queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false}]},"operations":[{"when":null,"actions":[{"targetValue":"HIGH","id":"595397fc-f7f5-4fbd-936b-1a7ad5ae88ae","type":"SET_PROPERTY","targetProperty":"alertLevel"},{"type":"CREATE_ALERT","id":"69e7809d-8003-44d8-9a9b-d277868e079a"}]}],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} + {"data":{"questionRuleInstance":{"id":"d3052389-8599-439e-a9e8-f1827ef4eacc","name":"tf-provider-test-rule","collectionId":null,"description":"Test","version":2,"specVersion":1,"latest":true,"pollingInterval":"ONE_WEEK","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":true,"ignorePreviousResults":false,"questionId":null,"question":{"queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false}]},"operations":[{"when":null,"actions":[{"targetValue":"HIGH","id":"156ae2d8-a80f-4087-9602-00b66389631a","type":"SET_PROPERTY","targetProperty":"alertLevel"},{"type":"CREATE_ALERT","id":"fc2aff5f-9c5e-4234-b490-2bbfef32383b"}]}],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} headers: Access-Control-Allow-Credentials: - "true" Content-Length: - - "880" + - "900" Content-Security-Policy: - 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self'' https: data:;form-action ''self'';frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src ''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests' Content-Type: @@ -390,7 +390,7 @@ interactions: - "0" status: 200 OK code: 200 - duration: 201.418416ms + duration: 442.071125ms - id: 5 request: proto: HTTP/1.1 @@ -399,17 +399,17 @@ interactions: content_length: 200 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nmutation DeleteRuleInstance ($id: ID!) {\n\tdeleteRuleInstance(id: $id) {\n\t\tid\n\t}\n}\n","variables":{"id":"d4ebcdb5-7bea-4e4e-9fd7-fd0b677ea2cc"},"operationName":"DeleteRuleInstance"}' + body: '{"query":"\nmutation DeleteRuleInstance ($id: ID!) {\n\tdeleteRuleInstance(id: $id) {\n\t\tid\n\t}\n}\n","variables":{"id":"d3052389-8599-439e-a9e8-f1827ef4eacc"},"operationName":"DeleteRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -420,7 +420,7 @@ interactions: content_length: 78 uncompressed: false body: | - {"data":{"deleteRuleInstance":{"id":"d4ebcdb5-7bea-4e4e-9fd7-fd0b677ea2cc"}}} + {"data":{"deleteRuleInstance":{"id":"d3052389-8599-439e-a9e8-f1827ef4eacc"}}} headers: Access-Control-Allow-Credentials: - "true" @@ -468,4 +468,4 @@ interactions: - "0" status: 200 OK code: 200 - duration: 234.444ms + duration: 200.050292ms diff --git a/jupiterone/cassettes/TestInlineRuleInstance_BasicImport.yaml b/jupiterone/cassettes/TestInlineRuleInstance_BasicImport.yaml index e4bbe97d..0fd0941f 100644 --- a/jupiterone/cassettes/TestInlineRuleInstance_BasicImport.yaml +++ b/jupiterone/cassettes/TestInlineRuleInstance_BasicImport.yaml @@ -6,20 +6,20 @@ interactions: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 1132 + content_length: 1114 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nmutation CreateInlineQuestionRuleInstance ($instance: CreateInlineQuestionRuleInstanceInput!) {\n\tcreateQuestionRuleInstance: createInlineQuestionRuleInstance(instance: $instance) {\n\t\tid\n\t\tversion\n\t\tspecVersion\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\tlabels {\n\t\t\tlabelName\n\t\t\tlabelValue\n\t\t}\n\t}\n}\n","variables":{"instance":{"question":{"queries":[{"query":"Find DataStore with classification=(''critical'' or ''sensitive'' or ''confidential'' or ''restricted'') and encrypted!=true","name":"query0","version":"v1","includeDeleted":false}]},"templates":null,"tags":["tf_acc:1","tf_acc:2"],"name":"tf-provider-test-rule","description":"test","specVersion":1,"operations":[],"outputs":["queries.query0.total","alertLevel"],"pollingInterval":"ONE_DAY","notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"remediationSteps":"","collectionId":"","labels":null,"j1Internal":false}},"operationName":"CreateInlineQuestionRuleInstance"}' + body: '{"query":"\nmutation CreateInlineQuestionRuleInstance ($instance: CreateInlineQuestionRuleInstanceInput!) {\n\tcreateQuestionRuleInstance: createInlineQuestionRuleInstance(instance: $instance) {\n\t\tid\n\t\tversion\n\t\tspecVersion\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\tlabels {\n\t\t\tlabelName\n\t\t\tlabelValue\n\t\t}\n\t}\n}\n","variables":{"instance":{"question":{"queries":[{"query":"Find DataStore with classification=(''critical'' or ''sensitive'' or ''confidential'' or ''restricted'') and encrypted!=true","name":"query0","version":"v1","includeDeleted":false}]},"templates":null,"tags":["tf_acc:1","tf_acc:2"],"name":"tf-provider-test-rule","description":"test","specVersion":1,"operations":[],"outputs":["queries.query0.total","alertLevel"],"pollingInterval":"ONE_DAY","notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"remediationSteps":"","labels":null,"j1Internal":false}},"operationName":"CreateInlineQuestionRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -30,7 +30,7 @@ interactions: content_length: 350 uncompressed: false body: | - {"data":{"createQuestionRuleInstance":{"id":"81a8c676-7155-4f4f-b755-9eab08be21ea","version":1,"specVersion":1,"question":{"queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false}]},"operations":[],"labels":[]}}} + {"data":{"createQuestionRuleInstance":{"id":"2cb574d2-0cf1-4f41-8b57-bfca2a6eb5cc","version":1,"specVersion":1,"question":{"queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false}]},"operations":[],"labels":[]}}} headers: Access-Control-Allow-Credentials: - "true" @@ -78,26 +78,26 @@ interactions: - "0" status: 200 OK code: 200 - duration: 609.287625ms + duration: 746.634084ms - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 632 + content_length: 650 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"81a8c676-7155-4f4f-b755-9eab08be21ea"},"operationName":"GetQuestionRuleInstance"}' + body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tcollectionId\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"2cb574d2-0cf1-4f41-8b57-bfca2a6eb5cc"},"operationName":"GetQuestionRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -105,15 +105,15 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 668 + content_length: 688 uncompressed: false body: | - {"data":{"questionRuleInstance":{"id":"81a8c676-7155-4f4f-b755-9eab08be21ea","name":"tf-provider-test-rule","description":"test","version":1,"specVersion":1,"latest":true,"pollingInterval":"ONE_DAY","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"questionId":null,"question":{"queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false}]},"operations":[],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} + {"data":{"questionRuleInstance":{"id":"2cb574d2-0cf1-4f41-8b57-bfca2a6eb5cc","name":"tf-provider-test-rule","collectionId":null,"description":"test","version":1,"specVersion":1,"latest":true,"pollingInterval":"ONE_DAY","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"questionId":null,"question":{"queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false}]},"operations":[],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} headers: Access-Control-Allow-Credentials: - "true" Content-Length: - - "668" + - "688" Content-Security-Policy: - 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self'' https: data:;form-action ''self'';frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src ''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests' Content-Type: @@ -156,7 +156,7 @@ interactions: - "0" status: 200 OK code: 200 - duration: 188.905125ms + duration: 219.746958ms - id: 2 request: proto: HTTP/1.1 @@ -165,17 +165,17 @@ interactions: content_length: 200 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nmutation DeleteRuleInstance ($id: ID!) {\n\tdeleteRuleInstance(id: $id) {\n\t\tid\n\t}\n}\n","variables":{"id":"81a8c676-7155-4f4f-b755-9eab08be21ea"},"operationName":"DeleteRuleInstance"}' + body: '{"query":"\nmutation DeleteRuleInstance ($id: ID!) {\n\tdeleteRuleInstance(id: $id) {\n\t\tid\n\t}\n}\n","variables":{"id":"2cb574d2-0cf1-4f41-8b57-bfca2a6eb5cc"},"operationName":"DeleteRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -186,7 +186,7 @@ interactions: content_length: 78 uncompressed: false body: | - {"data":{"deleteRuleInstance":{"id":"81a8c676-7155-4f4f-b755-9eab08be21ea"}}} + {"data":{"deleteRuleInstance":{"id":"2cb574d2-0cf1-4f41-8b57-bfca2a6eb5cc"}}} headers: Access-Control-Allow-Credentials: - "true" @@ -234,4 +234,4 @@ interactions: - "0" status: 200 OK code: 200 - duration: 200.725ms + duration: 228.711917ms diff --git a/jupiterone/cassettes/TestReferencedQuestionRule_Basic.yaml b/jupiterone/cassettes/TestReferencedQuestionRule_Basic.yaml index 1f772abb..f3914ef9 100644 --- a/jupiterone/cassettes/TestReferencedQuestionRule_Basic.yaml +++ b/jupiterone/cassettes/TestReferencedQuestionRule_Basic.yaml @@ -9,7 +9,7 @@ interactions: content_length: 601 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" body: '{"query":"\nmutation CreateQuestion ($question: CreateQuestionInput!) {\n\tcreateQuestion(question: $question) {\n\t\tid\n\t}\n}\n","variables":{"question":{"title":"tf-provider-test-rule","name":"","tags":["tf_acc:1","tf_acc:2"],"description":"Test","showTrend":false,"pollingInterval":"ONE_DAY","widgetId":"","queries":[{"query":"Find DataStore with classification=(''critical'' or ''sensitive'' or ''confidential'' or ''restricted'') and encrypted!=true","version":"v1","name":"query0","resultsAre":"INFORMATIVE","includeDeleted":false}],"compliance":[],"variables":null}},"operationName":"CreateQuestion"}' @@ -19,7 +19,7 @@ interactions: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -30,7 +30,7 @@ interactions: content_length: 74 uncompressed: false body: | - {"data":{"createQuestion":{"id":"a4a81b66-72f6-4373-8999-9b26c5aa7d02"}}} + {"data":{"createQuestion":{"id":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81"}}} headers: Access-Control-Allow-Credentials: - "true" @@ -78,26 +78,26 @@ interactions: - "0" status: 200 OK code: 200 - duration: 722.541958ms + duration: 2.225157833s - id: 1 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 996 + content_length: 978 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nmutation CreateReferencedQuestionRuleInstance ($instance: CreateReferencedQuestionRuleInstanceInput!) {\n\tcreateQuestionRuleInstance: createReferencedQuestionRuleInstance(instance: $instance) {\n\t\tid\n\t\tversion\n\t\tspecVersion\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t}\n}\n","variables":{"instance":{"questionId":"a4a81b66-72f6-4373-8999-9b26c5aa7d02","templates":null,"tags":["tf_acc:1","tf_acc:2"],"name":"tf-provider-test-rule","description":"Test","specVersion":1,"operations":[{"when":{"condition":"{{queries.query0.total != 0}}","specVersion":1,"type":"FILTER"},"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY"},{"type":"CREATE_ALERT"}]}],"outputs":["queries.query0.total","alertLevel"],"pollingInterval":"ONE_WEEK","notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"remediationSteps":"","collectionId":"","labels":null}},"operationName":"CreateReferencedQuestionRuleInstance"}' + body: '{"query":"\nmutation CreateReferencedQuestionRuleInstance ($instance: CreateReferencedQuestionRuleInstanceInput!) {\n\tcreateQuestionRuleInstance: createReferencedQuestionRuleInstance(instance: $instance) {\n\t\tid\n\t\tversion\n\t\tspecVersion\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t}\n}\n","variables":{"instance":{"questionId":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81","templates":null,"tags":["tf_acc:1","tf_acc:2"],"name":"tf-provider-test-rule","description":"Test","specVersion":1,"operations":[{"when":{"condition":"{{queries.query0.total != 0}}","specVersion":1,"type":"FILTER"},"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY"},{"type":"CREATE_ALERT"}]}],"outputs":["queries.query0.total","alertLevel"],"pollingInterval":"ONE_WEEK","notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"remediationSteps":"","labels":null}},"operationName":"CreateReferencedQuestionRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -108,7 +108,7 @@ interactions: content_length: 415 uncompressed: false body: | - {"data":{"createQuestionRuleInstance":{"id":"5101a668-a7d9-463d-9d74-64c91b3f2d10","version":1,"specVersion":1,"operations":[{"when":{"condition":"{{queries.query0.total != 0}}","specVersion":1,"type":"FILTER"},"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY","id":"6de9cc35-e43d-45eb-899c-a53b134ec596"},{"type":"CREATE_ALERT","id":"1bc23598-5a44-4698-baf0-062d8b7779b5"}]}]}}} + {"data":{"createQuestionRuleInstance":{"id":"d525e04f-3aa2-4835-845f-15c6823e801d","version":1,"specVersion":1,"operations":[{"when":{"condition":"{{queries.query0.total != 0}}","specVersion":1,"type":"FILTER"},"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY","id":"ae70faf9-ce53-4925-acc7-4c1876353157"},{"type":"CREATE_ALERT","id":"b6ef40e1-abb0-4f21-8013-5843d1367a10"}]}]}}} headers: Access-Control-Allow-Credentials: - "true" @@ -156,7 +156,7 @@ interactions: - "0" status: 200 OK code: 200 - duration: 966.789792ms + duration: 1.284597417s - id: 2 request: proto: HTTP/1.1 @@ -165,17 +165,17 @@ interactions: content_length: 434 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nquery GetQuestionById ($id: ID!) {\n\tquestion(id: $id) {\n\t\tid\n\t\ttitle\n\t\tdescription\n\t\tshowTrend\n\t\tpollingInterval\n\t\tqueries {\n\t\t\tname\n\t\t\tquery\n\t\t\tversion\n\t\t\tincludeDeleted\n\t\t\tresultsAre\n\t\t}\n\t\ttags\n\t\tcompliance {\n\t\t\tstandard\n\t\t\trequirements\n\t\t\tcontrols\n\t\t}\n\t}\n}\n","variables":{"id":"a4a81b66-72f6-4373-8999-9b26c5aa7d02"},"operationName":"GetQuestionById"}' + body: '{"query":"\nquery GetQuestionById ($id: ID!) {\n\tquestion(id: $id) {\n\t\tid\n\t\ttitle\n\t\tdescription\n\t\tshowTrend\n\t\tpollingInterval\n\t\tqueries {\n\t\t\tname\n\t\t\tquery\n\t\t\tversion\n\t\t\tincludeDeleted\n\t\t\tresultsAre\n\t\t}\n\t\ttags\n\t\tcompliance {\n\t\t\tstandard\n\t\t\trequirements\n\t\t\tcontrols\n\t\t}\n\t}\n}\n","variables":{"id":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81"},"operationName":"GetQuestionById"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -186,7 +186,7 @@ interactions: content_length: 436 uncompressed: false body: | - {"data":{"question":{"id":"a4a81b66-72f6-4373-8999-9b26c5aa7d02","title":"tf-provider-test-rule","description":"Test","showTrend":false,"pollingInterval":"ONE_DAY","queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false,"resultsAre":"INFORMATIVE"}],"tags":["tf_acc:1","tf_acc:2"],"compliance":[]}}} + {"data":{"question":{"id":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81","title":"tf-provider-test-rule","description":"Test","showTrend":false,"pollingInterval":"ONE_DAY","queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false,"resultsAre":"INFORMATIVE"}],"tags":["tf_acc:1","tf_acc:2"],"compliance":[]}}} headers: Access-Control-Allow-Credentials: - "true" @@ -234,26 +234,26 @@ interactions: - "0" status: 200 OK code: 200 - duration: 248.231791ms + duration: 349.569167ms - id: 3 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 632 + content_length: 650 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"5101a668-a7d9-463d-9d74-64c91b3f2d10"},"operationName":"GetQuestionRuleInstance"}' + body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tcollectionId\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"d525e04f-3aa2-4835-845f-15c6823e801d"},"operationName":"GetQuestionRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -261,15 +261,15 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 796 + content_length: 816 uncompressed: false body: | - {"data":{"questionRuleInstance":{"id":"5101a668-a7d9-463d-9d74-64c91b3f2d10","name":"tf-provider-test-rule","description":"Test","version":1,"specVersion":1,"latest":true,"pollingInterval":"ONE_WEEK","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"questionId":"a4a81b66-72f6-4373-8999-9b26c5aa7d02","question":null,"operations":[{"when":{"type":"FILTER","condition":"{{queries.query0.total != 0}}","specVersion":1},"actions":[{"targetValue":"HIGH","id":"6de9cc35-e43d-45eb-899c-a53b134ec596","type":"SET_PROPERTY","targetProperty":"alertLevel"},{"type":"CREATE_ALERT","id":"1bc23598-5a44-4698-baf0-062d8b7779b5"}]}],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} + {"data":{"questionRuleInstance":{"id":"d525e04f-3aa2-4835-845f-15c6823e801d","name":"tf-provider-test-rule","collectionId":null,"description":"Test","version":1,"specVersion":1,"latest":true,"pollingInterval":"ONE_WEEK","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"questionId":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81","question":null,"operations":[{"when":{"type":"FILTER","condition":"{{queries.query0.total != 0}}","specVersion":1},"actions":[{"targetValue":"HIGH","id":"ae70faf9-ce53-4925-acc7-4c1876353157","type":"SET_PROPERTY","targetProperty":"alertLevel"},{"type":"CREATE_ALERT","id":"b6ef40e1-abb0-4f21-8013-5843d1367a10"}]}],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} headers: Access-Control-Allow-Credentials: - "true" Content-Length: - - "796" + - "816" Content-Security-Policy: - 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self'' https: data:;form-action ''self'';frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src ''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests' Content-Type: @@ -312,7 +312,7 @@ interactions: - "0" status: 200 OK code: 200 - duration: 185.999917ms + duration: 149.247333ms - id: 4 request: proto: HTTP/1.1 @@ -321,17 +321,17 @@ interactions: content_length: 434 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nquery GetQuestionById ($id: ID!) {\n\tquestion(id: $id) {\n\t\tid\n\t\ttitle\n\t\tdescription\n\t\tshowTrend\n\t\tpollingInterval\n\t\tqueries {\n\t\t\tname\n\t\t\tquery\n\t\t\tversion\n\t\t\tincludeDeleted\n\t\t\tresultsAre\n\t\t}\n\t\ttags\n\t\tcompliance {\n\t\t\tstandard\n\t\t\trequirements\n\t\t\tcontrols\n\t\t}\n\t}\n}\n","variables":{"id":"a4a81b66-72f6-4373-8999-9b26c5aa7d02"},"operationName":"GetQuestionById"}' + body: '{"query":"\nquery GetQuestionById ($id: ID!) {\n\tquestion(id: $id) {\n\t\tid\n\t\ttitle\n\t\tdescription\n\t\tshowTrend\n\t\tpollingInterval\n\t\tqueries {\n\t\t\tname\n\t\t\tquery\n\t\t\tversion\n\t\t\tincludeDeleted\n\t\t\tresultsAre\n\t\t}\n\t\ttags\n\t\tcompliance {\n\t\t\tstandard\n\t\t\trequirements\n\t\t\tcontrols\n\t\t}\n\t}\n}\n","variables":{"id":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81"},"operationName":"GetQuestionById"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -342,7 +342,7 @@ interactions: content_length: 436 uncompressed: false body: | - {"data":{"question":{"id":"a4a81b66-72f6-4373-8999-9b26c5aa7d02","title":"tf-provider-test-rule","description":"Test","showTrend":false,"pollingInterval":"ONE_DAY","queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false,"resultsAre":"INFORMATIVE"}],"tags":["tf_acc:1","tf_acc:2"],"compliance":[]}}} + {"data":{"question":{"id":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81","title":"tf-provider-test-rule","description":"Test","showTrend":false,"pollingInterval":"ONE_DAY","queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false,"resultsAre":"INFORMATIVE"}],"tags":["tf_acc:1","tf_acc:2"],"compliance":[]}}} headers: Access-Control-Allow-Credentials: - "true" @@ -390,26 +390,26 @@ interactions: - "0" status: 200 OK code: 200 - duration: 241.0375ms + duration: 233.255583ms - id: 5 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 632 + content_length: 650 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"5101a668-a7d9-463d-9d74-64c91b3f2d10"},"operationName":"GetQuestionRuleInstance"}' + body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tcollectionId\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"d525e04f-3aa2-4835-845f-15c6823e801d"},"operationName":"GetQuestionRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -417,15 +417,15 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 796 + content_length: 816 uncompressed: false body: | - {"data":{"questionRuleInstance":{"id":"5101a668-a7d9-463d-9d74-64c91b3f2d10","name":"tf-provider-test-rule","description":"Test","version":1,"specVersion":1,"latest":true,"pollingInterval":"ONE_WEEK","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"questionId":"a4a81b66-72f6-4373-8999-9b26c5aa7d02","question":null,"operations":[{"when":{"type":"FILTER","condition":"{{queries.query0.total != 0}}","specVersion":1},"actions":[{"targetValue":"HIGH","id":"6de9cc35-e43d-45eb-899c-a53b134ec596","type":"SET_PROPERTY","targetProperty":"alertLevel"},{"type":"CREATE_ALERT","id":"1bc23598-5a44-4698-baf0-062d8b7779b5"}]}],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} + {"data":{"questionRuleInstance":{"id":"d525e04f-3aa2-4835-845f-15c6823e801d","name":"tf-provider-test-rule","collectionId":null,"description":"Test","version":1,"specVersion":1,"latest":true,"pollingInterval":"ONE_WEEK","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"questionId":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81","question":null,"operations":[{"when":{"type":"FILTER","condition":"{{queries.query0.total != 0}}","specVersion":1},"actions":[{"targetValue":"HIGH","id":"ae70faf9-ce53-4925-acc7-4c1876353157","type":"SET_PROPERTY","targetProperty":"alertLevel"},{"type":"CREATE_ALERT","id":"b6ef40e1-abb0-4f21-8013-5843d1367a10"}]}],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} headers: Access-Control-Allow-Credentials: - "true" Content-Length: - - "796" + - "816" Content-Security-Policy: - 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self'' https: data:;form-action ''self'';frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src ''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests' Content-Type: @@ -468,26 +468,26 @@ interactions: - "0" status: 200 OK code: 200 - duration: 194.606708ms + duration: 150.993167ms - id: 6 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 956 + content_length: 938 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nmutation UpdateReferencedQuestionRuleInstance ($instance: UpdateReferencedQuestionRuleInstanceInput!) {\n\tupdateReferencedQuestionRuleInstance(instance: $instance) {\n\t\tversion\n\t\tspecVersion\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t}\n}\n","variables":{"instance":{"questionId":"a4a81b66-72f6-4373-8999-9b26c5aa7d02","id":"5101a668-a7d9-463d-9d74-64c91b3f2d10","version":1,"state":{"actions":null},"templates":null,"tags":["tf_acc:1","tf_acc:2"],"name":"tf-provider-test-rule","description":"Test","specVersion":1,"operations":[{"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY"},{"type":"CREATE_ALERT"}]}],"outputs":["queries.query0.total","alertLevel"],"pollingInterval":"ONE_WEEK","notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"remediationSteps":"","collectionId":"","labels":null}},"operationName":"UpdateReferencedQuestionRuleInstance"}' + body: '{"query":"\nmutation UpdateReferencedQuestionRuleInstance ($instance: UpdateReferencedQuestionRuleInstanceInput!) {\n\tupdateReferencedQuestionRuleInstance(instance: $instance) {\n\t\tversion\n\t\tspecVersion\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t}\n}\n","variables":{"instance":{"questionId":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81","id":"d525e04f-3aa2-4835-845f-15c6823e801d","version":1,"state":{"actions":null},"templates":null,"tags":["tf_acc:1","tf_acc:2"],"name":"tf-provider-test-rule","description":"Test","specVersion":1,"operations":[{"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY"},{"type":"CREATE_ALERT"}]}],"outputs":["queries.query0.total","alertLevel"],"pollingInterval":"ONE_WEEK","notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"remediationSteps":"","labels":null}},"operationName":"UpdateReferencedQuestionRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -498,7 +498,7 @@ interactions: content_length: 308 uncompressed: false body: | - {"data":{"updateReferencedQuestionRuleInstance":{"version":2,"specVersion":1,"operations":[{"when":null,"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY","id":"641f86cf-93f1-498f-ae9c-0c7ed6dd6038"},{"type":"CREATE_ALERT","id":"22afacc5-f05e-4de2-98e7-ebf6c98f50e2"}]}]}}} + {"data":{"updateReferencedQuestionRuleInstance":{"version":2,"specVersion":1,"operations":[{"when":null,"actions":[{"targetProperty":"alertLevel","targetValue":"HIGH","type":"SET_PROPERTY","id":"489e0b52-e4f6-45b7-99cd-01764a737d99"},{"type":"CREATE_ALERT","id":"59e08d05-832c-4921-9829-62064db4bb32"}]}]}}} headers: Access-Control-Allow-Credentials: - "true" @@ -546,7 +546,7 @@ interactions: - "0" status: 200 OK code: 200 - duration: 702.913166ms + duration: 672.419666ms - id: 7 request: proto: HTTP/1.1 @@ -555,17 +555,17 @@ interactions: content_length: 434 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nquery GetQuestionById ($id: ID!) {\n\tquestion(id: $id) {\n\t\tid\n\t\ttitle\n\t\tdescription\n\t\tshowTrend\n\t\tpollingInterval\n\t\tqueries {\n\t\t\tname\n\t\t\tquery\n\t\t\tversion\n\t\t\tincludeDeleted\n\t\t\tresultsAre\n\t\t}\n\t\ttags\n\t\tcompliance {\n\t\t\tstandard\n\t\t\trequirements\n\t\t\tcontrols\n\t\t}\n\t}\n}\n","variables":{"id":"a4a81b66-72f6-4373-8999-9b26c5aa7d02"},"operationName":"GetQuestionById"}' + body: '{"query":"\nquery GetQuestionById ($id: ID!) {\n\tquestion(id: $id) {\n\t\tid\n\t\ttitle\n\t\tdescription\n\t\tshowTrend\n\t\tpollingInterval\n\t\tqueries {\n\t\t\tname\n\t\t\tquery\n\t\t\tversion\n\t\t\tincludeDeleted\n\t\t\tresultsAre\n\t\t}\n\t\ttags\n\t\tcompliance {\n\t\t\tstandard\n\t\t\trequirements\n\t\t\tcontrols\n\t\t}\n\t}\n}\n","variables":{"id":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81"},"operationName":"GetQuestionById"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -576,7 +576,7 @@ interactions: content_length: 436 uncompressed: false body: | - {"data":{"question":{"id":"a4a81b66-72f6-4373-8999-9b26c5aa7d02","title":"tf-provider-test-rule","description":"Test","showTrend":false,"pollingInterval":"ONE_DAY","queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false,"resultsAre":"INFORMATIVE"}],"tags":["tf_acc:1","tf_acc:2"],"compliance":[]}}} + {"data":{"question":{"id":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81","title":"tf-provider-test-rule","description":"Test","showTrend":false,"pollingInterval":"ONE_DAY","queries":[{"name":"query0","query":"Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true","version":"v1","includeDeleted":false,"resultsAre":"INFORMATIVE"}],"tags":["tf_acc:1","tf_acc:2"],"compliance":[]}}} headers: Access-Control-Allow-Credentials: - "true" @@ -624,26 +624,26 @@ interactions: - "0" status: 200 OK code: 200 - duration: 263.366083ms + duration: 214.978708ms - id: 8 request: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 632 + content_length: 650 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"5101a668-a7d9-463d-9d74-64c91b3f2d10"},"operationName":"GetQuestionRuleInstance"}' + body: '{"query":"\nquery GetQuestionRuleInstance ($id: ID!) {\n\tquestionRuleInstance(id: $id) {\n\t\tid\n\t\tname\n\t\tcollectionId\n\t\tdescription\n\t\tversion\n\t\tspecVersion\n\t\tlatest\n\t\tpollingInterval\n\t\tdeleted\n\t\ttype\n\t\ttemplates\n\t\tnotifyOnFailure\n\t\ttriggerActionsOnNewEntitiesOnly\n\t\tignorePreviousResults\n\t\tquestionId\n\t\tquestion {\n\t\t\tqueries {\n\t\t\t\tname\n\t\t\t\tquery\n\t\t\t\tversion\n\t\t\t\tincludeDeleted\n\t\t\t}\n\t\t}\n\t\toperations {\n\t\t\twhen\n\t\t\tactions\n\t\t}\n\t\toutputs\n\t\ttags\n\t}\n}\n","variables":{"id":"d525e04f-3aa2-4835-845f-15c6823e801d"},"operationName":"GetQuestionRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -651,15 +651,15 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 723 + content_length: 743 uncompressed: false body: | - {"data":{"questionRuleInstance":{"id":"5101a668-a7d9-463d-9d74-64c91b3f2d10","name":"tf-provider-test-rule","description":"Test","version":2,"specVersion":1,"latest":true,"pollingInterval":"ONE_WEEK","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"questionId":"a4a81b66-72f6-4373-8999-9b26c5aa7d02","question":null,"operations":[{"when":null,"actions":[{"targetValue":"HIGH","id":"641f86cf-93f1-498f-ae9c-0c7ed6dd6038","type":"SET_PROPERTY","targetProperty":"alertLevel"},{"type":"CREATE_ALERT","id":"22afacc5-f05e-4de2-98e7-ebf6c98f50e2"}]}],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} + {"data":{"questionRuleInstance":{"id":"d525e04f-3aa2-4835-845f-15c6823e801d","name":"tf-provider-test-rule","collectionId":null,"description":"Test","version":2,"specVersion":1,"latest":true,"pollingInterval":"ONE_WEEK","deleted":false,"type":"QUESTION","templates":null,"notifyOnFailure":false,"triggerActionsOnNewEntitiesOnly":false,"ignorePreviousResults":false,"questionId":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81","question":null,"operations":[{"when":null,"actions":[{"targetValue":"HIGH","id":"489e0b52-e4f6-45b7-99cd-01764a737d99","type":"SET_PROPERTY","targetProperty":"alertLevel"},{"type":"CREATE_ALERT","id":"59e08d05-832c-4921-9829-62064db4bb32"}]}],"outputs":["queries.query0.total","alertLevel"],"tags":["tf_acc:1","tf_acc:2"]}}} headers: Access-Control-Allow-Credentials: - "true" Content-Length: - - "723" + - "743" Content-Security-Policy: - 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self'' https: data:;form-action ''self'';frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src ''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests' Content-Type: @@ -702,7 +702,7 @@ interactions: - "0" status: 200 OK code: 200 - duration: 197.696ms + duration: 156.036917ms - id: 9 request: proto: HTTP/1.1 @@ -711,17 +711,17 @@ interactions: content_length: 200 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nmutation DeleteRuleInstance ($id: ID!) {\n\tdeleteRuleInstance(id: $id) {\n\t\tid\n\t}\n}\n","variables":{"id":"5101a668-a7d9-463d-9d74-64c91b3f2d10"},"operationName":"DeleteRuleInstance"}' + body: '{"query":"\nmutation DeleteRuleInstance ($id: ID!) {\n\tdeleteRuleInstance(id: $id) {\n\t\tid\n\t}\n}\n","variables":{"id":"d525e04f-3aa2-4835-845f-15c6823e801d"},"operationName":"DeleteRuleInstance"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -732,7 +732,7 @@ interactions: content_length: 78 uncompressed: false body: | - {"data":{"deleteRuleInstance":{"id":"5101a668-a7d9-463d-9d74-64c91b3f2d10"}}} + {"data":{"deleteRuleInstance":{"id":"d525e04f-3aa2-4835-845f-15c6823e801d"}}} headers: Access-Control-Allow-Credentials: - "true" @@ -780,7 +780,7 @@ interactions: - "0" status: 200 OK code: 200 - duration: 314.756333ms + duration: 401.343208ms - id: 10 request: proto: HTTP/1.1 @@ -789,17 +789,17 @@ interactions: content_length: 188 transfer_encoding: [] trailer: {} - host: graphql.us.jupiterone.io + host: graphql.dev.jupiterone.io remote_addr: "" request_uri: "" - body: '{"query":"\nmutation DeleteQuestion ($id: ID!) {\n\tdeleteQuestion(id: $id) {\n\t\tid\n\t}\n}\n","variables":{"id":"a4a81b66-72f6-4373-8999-9b26c5aa7d02"},"operationName":"DeleteQuestion"}' + body: '{"query":"\nmutation DeleteQuestion ($id: ID!) {\n\tdeleteQuestion(id: $id) {\n\t\tid\n\t}\n}\n","variables":{"id":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81"},"operationName":"DeleteQuestion"}' form: {} headers: Cache-Control: - no-cache Content-Type: - application/json - url: https://graphql.us.jupiterone.io/ + url: https://graphql.dev.jupiterone.io/ method: POST response: proto: HTTP/2.0 @@ -810,7 +810,7 @@ interactions: content_length: 74 uncompressed: false body: | - {"data":{"deleteQuestion":{"id":"a4a81b66-72f6-4373-8999-9b26c5aa7d02"}}} + {"data":{"deleteQuestion":{"id":"7d2f7921-9c07-4b92-836b-8a4ee4a44a81"}}} headers: Access-Control-Allow-Credentials: - "true" @@ -858,4 +858,4 @@ interactions: - "0" status: 200 OK code: 200 - duration: 507.340583ms + duration: 392.906125ms diff --git a/jupiterone/cassettes/TestResourcePermission_Basic.yaml b/jupiterone/cassettes/TestResourcePermission_Basic.yaml new file mode 100644 index 00000000..558c5397 --- /dev/null +++ b/jupiterone/cassettes/TestResourcePermission_Basic.yaml @@ -0,0 +1,159 @@ +--- +version: 2 +interactions: + - id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 519 + transfer_encoding: [] + trailer: {} + host: graphql.dev.jupiterone.io + remote_addr: "" + request_uri: "" + body: '{"query":"\nmutation SetResourcePermission ($input: SetResourcePermissionInput!) {\n\tsetResourcePermission(input: $input) {\n\t\tcanCreate\n\t\tcanDelete\n\t\tcanRead\n\t\tcanUpdate\n\t\tresourceArea\n\t\tresourceId\n\t\tresourceType\n\t\tsubjectId\n\t\tsubjectType\n\t}\n}\n","variables":{"input":{"subjectType":"group","subjectId":"example-group-id","resourceArea":"rule","resourceType":"*","resourceId":"*","canCreate":true,"canRead":true,"canUpdate":true,"canDelete":true}},"operationName":"SetResourcePermission"}' + form: {} + headers: + Cache-Control: + - no-cache + Content-Type: + - application/json + url: https://graphql.dev.jupiterone.io/ + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 214 + uncompressed: false + body: | + {"data":{"setResourcePermission":{"canCreate":true,"canDelete":true,"canRead":true,"canUpdate":true,"resourceArea":"rule","resourceId":"*","resourceType":"*","subjectId":"example-group-id","subjectType":"group"}}} + headers: + Access-Control-Allow-Credentials: + - "true" + Content-Length: + - "214" + Content-Security-Policy: + - 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self'' https: data:;form-action ''self'';frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src ''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests' + Content-Type: + - application/json + Cross-Origin-Embedder-Policy: + - require-corp + Cross-Origin-Opener-Policy: + - same-origin + Cross-Origin-Resource-Policy: + - same-origin + Expect-Ct: + - max-age=0 + Origin-Agent-Cluster: + - ?1 + Ratelimit-Limit: + - "1000" + Ratelimit-Remaining: + - "999" + Ratelimit-Requested: + - "1" + Ratelimit-Reset: + - "1" + Referrer-Policy: + - no-referrer + Strict-Transport-Security: + - max-age=15552000; includeSubDomains + Vary: + - Origin + X-Content-Type-Options: + - nosniff + X-Dns-Prefetch-Control: + - "off" + X-Download-Options: + - noopen + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Xss-Protection: + - "0" + status: 200 OK + code: 200 + duration: 664.85025ms + - id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 336 + transfer_encoding: [] + trailer: {} + host: graphql.dev.jupiterone.io + remote_addr: "" + request_uri: "" + body: '{"query":"\nmutation DeleteResourcePermission ($input: DeleteResourcePermissionInput!) {\n\tdeleteResourcePermission(input: $input) {\n\t\tsuccess\n\t}\n}\n","variables":{"input":{"subjectType":"group","subjectId":"example-group-id","resourceArea":"rule","resourceType":"*","resourceId":"*"}},"operationName":"DeleteResourcePermission"}' + form: {} + headers: + Cache-Control: + - no-cache + Content-Type: + - application/json + url: https://graphql.dev.jupiterone.io/ + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + transfer_encoding: [] + trailer: {} + content_length: 55 + uncompressed: false + body: | + {"data":{"deleteResourcePermission":{"success":true}}} + headers: + Access-Control-Allow-Credentials: + - "true" + Content-Length: + - "55" + Content-Security-Policy: + - 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self'' https: data:;form-action ''self'';frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src ''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests' + Content-Type: + - application/json + Cross-Origin-Embedder-Policy: + - require-corp + Cross-Origin-Opener-Policy: + - same-origin + Cross-Origin-Resource-Policy: + - same-origin + Expect-Ct: + - max-age=0 + Origin-Agent-Cluster: + - ?1 + Ratelimit-Limit: + - "1000" + Ratelimit-Remaining: + - "999" + Ratelimit-Requested: + - "1" + Ratelimit-Reset: + - "1" + Referrer-Policy: + - no-referrer + Strict-Transport-Security: + - max-age=15552000; includeSubDomains + Vary: + - Origin + X-Content-Type-Options: + - nosniff + X-Dns-Prefetch-Control: + - "off" + X-Download-Options: + - noopen + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Xss-Protection: + - "0" + status: 200 OK + code: 200 + duration: 234.689667ms diff --git a/jupiterone/internal/client/generated.go b/jupiterone/internal/client/generated.go index ab1dfc28..e4e895ba 100644 --- a/jupiterone/internal/client/generated.go +++ b/jupiterone/internal/client/generated.go @@ -491,7 +491,7 @@ type CreateInlineQuestionRuleInstanceInput struct { TriggerActionsOnNewEntitiesOnly bool `json:"triggerActionsOnNewEntitiesOnly"` IgnorePreviousResults bool `json:"ignorePreviousResults"` RemediationSteps string `json:"remediationSteps"` - CollectionId string `json:"collectionId"` + CollectionId string `json:"collectionId,omitempty"` Labels []RuleInstanceLabelInput `json:"labels"` J1Internal bool `json:"j1Internal"` } @@ -1012,7 +1012,7 @@ type CreateReferencedQuestionRuleInstanceInput struct { TriggerActionsOnNewEntitiesOnly bool `json:"triggerActionsOnNewEntitiesOnly"` IgnorePreviousResults bool `json:"ignorePreviousResults"` RemediationSteps string `json:"remediationSteps"` - CollectionId string `json:"collectionId"` + CollectionId string `json:"collectionId,omitempty"` Labels []RuleInstanceLabelInput `json:"labels"` } @@ -1353,6 +1353,49 @@ func (v *DeleteQuestionResponse) GetDeleteQuestion() DeleteQuestionDeleteQuestio return v.DeleteQuestion } +// DeleteResourcePermissionDeleteResourcePermissionDeleteInfo includes the requested fields of the GraphQL type DeleteInfo. +type DeleteResourcePermissionDeleteResourcePermissionDeleteInfo struct { + Success bool `json:"success"` +} + +// GetSuccess returns DeleteResourcePermissionDeleteResourcePermissionDeleteInfo.Success, and is useful for accessing the field via an interface. +func (v *DeleteResourcePermissionDeleteResourcePermissionDeleteInfo) GetSuccess() bool { + return v.Success +} + +type DeleteResourcePermissionInput struct { + SubjectType string `json:"subjectType"` + SubjectId string `json:"subjectId"` + ResourceArea string `json:"resourceArea"` + ResourceType string `json:"resourceType"` + ResourceId string `json:"resourceId"` +} + +// GetSubjectType returns DeleteResourcePermissionInput.SubjectType, and is useful for accessing the field via an interface. +func (v *DeleteResourcePermissionInput) GetSubjectType() string { return v.SubjectType } + +// GetSubjectId returns DeleteResourcePermissionInput.SubjectId, and is useful for accessing the field via an interface. +func (v *DeleteResourcePermissionInput) GetSubjectId() string { return v.SubjectId } + +// GetResourceArea returns DeleteResourcePermissionInput.ResourceArea, and is useful for accessing the field via an interface. +func (v *DeleteResourcePermissionInput) GetResourceArea() string { return v.ResourceArea } + +// GetResourceType returns DeleteResourcePermissionInput.ResourceType, and is useful for accessing the field via an interface. +func (v *DeleteResourcePermissionInput) GetResourceType() string { return v.ResourceType } + +// GetResourceId returns DeleteResourcePermissionInput.ResourceId, and is useful for accessing the field via an interface. +func (v *DeleteResourcePermissionInput) GetResourceId() string { return v.ResourceId } + +// DeleteResourcePermissionResponse is returned by DeleteResourcePermission on success. +type DeleteResourcePermissionResponse struct { + DeleteResourcePermission DeleteResourcePermissionDeleteResourcePermissionDeleteInfo `json:"deleteResourcePermission"` +} + +// GetDeleteResourcePermission returns DeleteResourcePermissionResponse.DeleteResourcePermission, and is useful for accessing the field via an interface. +func (v *DeleteResourcePermissionResponse) GetDeleteResourcePermission() DeleteResourcePermissionDeleteResourcePermissionDeleteInfo { + return v.DeleteResourcePermission +} + // DeleteRuleInstanceDeleteRuleInstanceDeleteRuleInstanceResult includes the requested fields of the GraphQL type DeleteRuleInstanceResult. type DeleteRuleInstanceDeleteRuleInstanceDeleteRuleInstanceResult struct { Id string `json:"id"` @@ -1947,6 +1990,7 @@ func (v *GetQuestionByIdResponse) GetQuestion() GetQuestionByIdQuestion { return type GetQuestionRuleInstanceQuestionRuleInstance struct { Id string `json:"id"` Name string `json:"name"` + CollectionId string `json:"collectionId"` Description string `json:"description"` Version int `json:"version"` SpecVersion int `json:"specVersion"` @@ -1971,6 +2015,9 @@ func (v *GetQuestionRuleInstanceQuestionRuleInstance) GetId() string { return v. // GetName returns GetQuestionRuleInstanceQuestionRuleInstance.Name, and is useful for accessing the field via an interface. func (v *GetQuestionRuleInstanceQuestionRuleInstance) GetName() string { return v.Name } +// GetCollectionId returns GetQuestionRuleInstanceQuestionRuleInstance.CollectionId, and is useful for accessing the field via an interface. +func (v *GetQuestionRuleInstanceQuestionRuleInstance) GetCollectionId() string { return v.CollectionId } + // GetDescription returns GetQuestionRuleInstanceQuestionRuleInstance.Description, and is useful for accessing the field via an interface. func (v *GetQuestionRuleInstanceQuestionRuleInstance) GetDescription() string { return v.Description } @@ -2081,6 +2128,97 @@ func (v *GetQuestionRuleInstanceResponse) GetQuestionRuleInstance() GetQuestionR return v.QuestionRuleInstance } +// GetResourcePermissionGetResourcePermissionsIamResourcePermission includes the requested fields of the GraphQL type IamResourcePermission. +type GetResourcePermissionGetResourcePermissionsIamResourcePermission struct { + CanCreate bool `json:"canCreate"` + CanDelete bool `json:"canDelete"` + CanRead bool `json:"canRead"` + CanUpdate bool `json:"canUpdate"` + ResourceArea string `json:"resourceArea"` + ResourceId string `json:"resourceId"` + ResourceType string `json:"resourceType"` + SubjectId string `json:"subjectId"` + SubjectType string `json:"subjectType"` +} + +// GetCanCreate returns GetResourcePermissionGetResourcePermissionsIamResourcePermission.CanCreate, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionGetResourcePermissionsIamResourcePermission) GetCanCreate() bool { + return v.CanCreate +} + +// GetCanDelete returns GetResourcePermissionGetResourcePermissionsIamResourcePermission.CanDelete, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionGetResourcePermissionsIamResourcePermission) GetCanDelete() bool { + return v.CanDelete +} + +// GetCanRead returns GetResourcePermissionGetResourcePermissionsIamResourcePermission.CanRead, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionGetResourcePermissionsIamResourcePermission) GetCanRead() bool { + return v.CanRead +} + +// GetCanUpdate returns GetResourcePermissionGetResourcePermissionsIamResourcePermission.CanUpdate, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionGetResourcePermissionsIamResourcePermission) GetCanUpdate() bool { + return v.CanUpdate +} + +// GetResourceArea returns GetResourcePermissionGetResourcePermissionsIamResourcePermission.ResourceArea, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionGetResourcePermissionsIamResourcePermission) GetResourceArea() string { + return v.ResourceArea +} + +// GetResourceId returns GetResourcePermissionGetResourcePermissionsIamResourcePermission.ResourceId, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionGetResourcePermissionsIamResourcePermission) GetResourceId() string { + return v.ResourceId +} + +// GetResourceType returns GetResourcePermissionGetResourcePermissionsIamResourcePermission.ResourceType, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionGetResourcePermissionsIamResourcePermission) GetResourceType() string { + return v.ResourceType +} + +// GetSubjectId returns GetResourcePermissionGetResourcePermissionsIamResourcePermission.SubjectId, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionGetResourcePermissionsIamResourcePermission) GetSubjectId() string { + return v.SubjectId +} + +// GetSubjectType returns GetResourcePermissionGetResourcePermissionsIamResourcePermission.SubjectType, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionGetResourcePermissionsIamResourcePermission) GetSubjectType() string { + return v.SubjectType +} + +// GetResourcePermissionResponse is returned by GetResourcePermission on success. +type GetResourcePermissionResponse struct { + GetResourcePermissions []GetResourcePermissionGetResourcePermissionsIamResourcePermission `json:"getResourcePermissions"` +} + +// GetGetResourcePermissions returns GetResourcePermissionResponse.GetResourcePermissions, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionResponse) GetGetResourcePermissions() []GetResourcePermissionGetResourcePermissionsIamResourcePermission { + return v.GetResourcePermissions +} + +type GetResourcePermissionsFilter struct { + SubjectType string `json:"subjectType"` + SubjectId string `json:"subjectId"` + ResourceArea string `json:"resourceArea"` + ResourceType string `json:"resourceType"` + ResourceId string `json:"resourceId"` +} + +// GetSubjectType returns GetResourcePermissionsFilter.SubjectType, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionsFilter) GetSubjectType() string { return v.SubjectType } + +// GetSubjectId returns GetResourcePermissionsFilter.SubjectId, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionsFilter) GetSubjectId() string { return v.SubjectId } + +// GetResourceArea returns GetResourcePermissionsFilter.ResourceArea, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionsFilter) GetResourceArea() string { return v.ResourceArea } + +// GetResourceType returns GetResourcePermissionsFilter.ResourceType, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionsFilter) GetResourceType() string { return v.ResourceType } + +// GetResourceId returns GetResourcePermissionsFilter.ResourceId, and is useful for accessing the field via an interface. +func (v *GetResourcePermissionsFilter) GetResourceId() string { return v.ResourceId } + // GetUserGroupIamGetGroupIamGroup includes the requested fields of the GraphQL type IamGroup. type GetUserGroupIamGetGroupIamGroup struct { Id string `json:"id"` @@ -2725,6 +2863,113 @@ const ( SchedulerPollingIntervalOneWeek SchedulerPollingInterval = "ONE_WEEK" ) +type SetResourcePermissionInput struct { + SubjectType string `json:"subjectType"` + SubjectId string `json:"subjectId"` + ResourceArea string `json:"resourceArea"` + ResourceType string `json:"resourceType"` + ResourceId string `json:"resourceId"` + CanCreate bool `json:"canCreate"` + CanRead bool `json:"canRead"` + CanUpdate bool `json:"canUpdate"` + CanDelete bool `json:"canDelete"` +} + +// GetSubjectType returns SetResourcePermissionInput.SubjectType, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionInput) GetSubjectType() string { return v.SubjectType } + +// GetSubjectId returns SetResourcePermissionInput.SubjectId, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionInput) GetSubjectId() string { return v.SubjectId } + +// GetResourceArea returns SetResourcePermissionInput.ResourceArea, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionInput) GetResourceArea() string { return v.ResourceArea } + +// GetResourceType returns SetResourcePermissionInput.ResourceType, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionInput) GetResourceType() string { return v.ResourceType } + +// GetResourceId returns SetResourcePermissionInput.ResourceId, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionInput) GetResourceId() string { return v.ResourceId } + +// GetCanCreate returns SetResourcePermissionInput.CanCreate, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionInput) GetCanCreate() bool { return v.CanCreate } + +// GetCanRead returns SetResourcePermissionInput.CanRead, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionInput) GetCanRead() bool { return v.CanRead } + +// GetCanUpdate returns SetResourcePermissionInput.CanUpdate, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionInput) GetCanUpdate() bool { return v.CanUpdate } + +// GetCanDelete returns SetResourcePermissionInput.CanDelete, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionInput) GetCanDelete() bool { return v.CanDelete } + +// SetResourcePermissionResponse is returned by SetResourcePermission on success. +type SetResourcePermissionResponse struct { + SetResourcePermission SetResourcePermissionSetResourcePermissionIamResourcePermission `json:"setResourcePermission"` +} + +// GetSetResourcePermission returns SetResourcePermissionResponse.SetResourcePermission, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionResponse) GetSetResourcePermission() SetResourcePermissionSetResourcePermissionIamResourcePermission { + return v.SetResourcePermission +} + +// SetResourcePermissionSetResourcePermissionIamResourcePermission includes the requested fields of the GraphQL type IamResourcePermission. +type SetResourcePermissionSetResourcePermissionIamResourcePermission struct { + CanCreate bool `json:"canCreate"` + CanDelete bool `json:"canDelete"` + CanRead bool `json:"canRead"` + CanUpdate bool `json:"canUpdate"` + ResourceArea string `json:"resourceArea"` + ResourceId string `json:"resourceId"` + ResourceType string `json:"resourceType"` + SubjectId string `json:"subjectId"` + SubjectType string `json:"subjectType"` +} + +// GetCanCreate returns SetResourcePermissionSetResourcePermissionIamResourcePermission.CanCreate, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionSetResourcePermissionIamResourcePermission) GetCanCreate() bool { + return v.CanCreate +} + +// GetCanDelete returns SetResourcePermissionSetResourcePermissionIamResourcePermission.CanDelete, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionSetResourcePermissionIamResourcePermission) GetCanDelete() bool { + return v.CanDelete +} + +// GetCanRead returns SetResourcePermissionSetResourcePermissionIamResourcePermission.CanRead, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionSetResourcePermissionIamResourcePermission) GetCanRead() bool { + return v.CanRead +} + +// GetCanUpdate returns SetResourcePermissionSetResourcePermissionIamResourcePermission.CanUpdate, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionSetResourcePermissionIamResourcePermission) GetCanUpdate() bool { + return v.CanUpdate +} + +// GetResourceArea returns SetResourcePermissionSetResourcePermissionIamResourcePermission.ResourceArea, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionSetResourcePermissionIamResourcePermission) GetResourceArea() string { + return v.ResourceArea +} + +// GetResourceId returns SetResourcePermissionSetResourcePermissionIamResourcePermission.ResourceId, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionSetResourcePermissionIamResourcePermission) GetResourceId() string { + return v.ResourceId +} + +// GetResourceType returns SetResourcePermissionSetResourcePermissionIamResourcePermission.ResourceType, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionSetResourcePermissionIamResourcePermission) GetResourceType() string { + return v.ResourceType +} + +// GetSubjectId returns SetResourcePermissionSetResourcePermissionIamResourcePermission.SubjectId, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionSetResourcePermissionIamResourcePermission) GetSubjectId() string { + return v.SubjectId +} + +// GetSubjectType returns SetResourcePermissionSetResourcePermissionIamResourcePermission.SubjectType, and is useful for accessing the field via an interface. +func (v *SetResourcePermissionSetResourcePermissionIamResourcePermission) GetSubjectType() string { + return v.SubjectType +} + type UpdateComplianceFrameworkFields struct { Name string `json:"name"` WebLink string `json:"webLink"` @@ -2987,7 +3232,7 @@ type UpdateInlineQuestionRuleInstanceInput struct { TriggerActionsOnNewEntitiesOnly bool `json:"triggerActionsOnNewEntitiesOnly"` IgnorePreviousResults bool `json:"ignorePreviousResults"` RemediationSteps string `json:"remediationSteps,omitempty"` - CollectionId string `json:"collectionId"` + CollectionId string `json:"collectionId,omitempty"` Labels []RuleInstanceLabelInput `json:"labels"` } @@ -3285,7 +3530,7 @@ type UpdateReferencedQuestionRuleInstanceInput struct { TriggerActionsOnNewEntitiesOnly bool `json:"triggerActionsOnNewEntitiesOnly"` IgnorePreviousResults bool `json:"ignorePreviousResults"` RemediationSteps string `json:"remediationSteps"` - CollectionId string `json:"collectionId"` + CollectionId string `json:"collectionId,omitempty"` Labels []RuleInstanceLabelInput `json:"labels"` } @@ -3689,6 +3934,14 @@ type __DeleteQuestionInput struct { // GetId returns __DeleteQuestionInput.Id, and is useful for accessing the field via an interface. func (v *__DeleteQuestionInput) GetId() string { return v.Id } +// __DeleteResourcePermissionInput is used internally by genqlient +type __DeleteResourcePermissionInput struct { + Input DeleteResourcePermissionInput `json:"input"` +} + +// GetInput returns __DeleteResourcePermissionInput.Input, and is useful for accessing the field via an interface. +func (v *__DeleteResourcePermissionInput) GetInput() DeleteResourcePermissionInput { return v.Input } + // __DeleteRuleInstanceInput is used internally by genqlient type __DeleteRuleInstanceInput struct { Id string `json:"id"` @@ -3789,6 +4042,22 @@ type __GetQuestionRuleInstanceInput struct { // GetId returns __GetQuestionRuleInstanceInput.Id, and is useful for accessing the field via an interface. func (v *__GetQuestionRuleInstanceInput) GetId() string { return v.Id } +// __GetResourcePermissionInput is used internally by genqlient +type __GetResourcePermissionInput struct { + Filter GetResourcePermissionsFilter `json:"filter"` + Cursor string `json:"cursor"` + Limit int `json:"limit"` +} + +// GetFilter returns __GetResourcePermissionInput.Filter, and is useful for accessing the field via an interface. +func (v *__GetResourcePermissionInput) GetFilter() GetResourcePermissionsFilter { return v.Filter } + +// GetCursor returns __GetResourcePermissionInput.Cursor, and is useful for accessing the field via an interface. +func (v *__GetResourcePermissionInput) GetCursor() string { return v.Cursor } + +// GetLimit returns __GetResourcePermissionInput.Limit, and is useful for accessing the field via an interface. +func (v *__GetResourcePermissionInput) GetLimit() int { return v.Limit } + // __GetUserGroupInput is used internally by genqlient type __GetUserGroupInput struct { Id string `json:"id"` @@ -3861,6 +4130,14 @@ type __RevokeInvitationInput struct { // GetId returns __RevokeInvitationInput.Id, and is useful for accessing the field via an interface. func (v *__RevokeInvitationInput) GetId() string { return v.Id } +// __SetResourcePermissionInput is used internally by genqlient +type __SetResourcePermissionInput struct { + Input SetResourcePermissionInput `json:"input"` +} + +// GetInput returns __SetResourcePermissionInput.Input, and is useful for accessing the field via an interface. +func (v *__SetResourcePermissionInput) GetInput() SetResourcePermissionInput { return v.Input } + // __UpdateComplianceFrameworkInput is used internally by genqlient type __UpdateComplianceFrameworkInput struct { Input UpdateComplianceFrameworkInput `json:"input"` @@ -4731,6 +5008,38 @@ mutation DeleteQuestion ($id: ID!) { return &data, err } +func DeleteResourcePermission( + ctx context.Context, + client graphql.Client, + input DeleteResourcePermissionInput, +) (*DeleteResourcePermissionResponse, error) { + req := &graphql.Request{ + OpName: "DeleteResourcePermission", + Query: ` +mutation DeleteResourcePermission ($input: DeleteResourcePermissionInput!) { + deleteResourcePermission(input: $input) { + success + } +} +`, + Variables: &__DeleteResourcePermissionInput{ + Input: input, + }, + } + var err error + + var data DeleteResourcePermissionResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + func DeleteRuleInstance( ctx context.Context, client graphql.Client, @@ -5216,6 +5525,7 @@ query GetQuestionRuleInstance ($id: ID!) { questionRuleInstance(id: $id) { id name + collectionId description version specVersion @@ -5263,6 +5573,50 @@ query GetQuestionRuleInstance ($id: ID!) { return &data, err } +func GetResourcePermission( + ctx context.Context, + client graphql.Client, + filter GetResourcePermissionsFilter, + cursor string, + limit int, +) (*GetResourcePermissionResponse, error) { + req := &graphql.Request{ + OpName: "GetResourcePermission", + Query: ` +query GetResourcePermission ($filter: GetResourcePermissionsFilter!, $cursor: String, $limit: Int) { + getResourcePermissions(filter: $filter, cursor: $cursor, limit: $limit) { + canCreate + canDelete + canRead + canUpdate + resourceArea + resourceId + resourceType + subjectId + subjectType + } +} +`, + Variables: &__GetResourcePermissionInput{ + Filter: filter, + Cursor: cursor, + Limit: limit, + }, + } + var err error + + var data GetResourcePermissionResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + func GetUserGroup( ctx context.Context, client graphql.Client, @@ -5530,6 +5884,46 @@ mutation RevokeInvitation ($id: ID!) { return &data, err } +func SetResourcePermission( + ctx context.Context, + client graphql.Client, + input SetResourcePermissionInput, +) (*SetResourcePermissionResponse, error) { + req := &graphql.Request{ + OpName: "SetResourcePermission", + Query: ` +mutation SetResourcePermission ($input: SetResourcePermissionInput!) { + setResourcePermission(input: $input) { + canCreate + canDelete + canRead + canUpdate + resourceArea + resourceId + resourceType + subjectId + subjectType + } +} +`, + Variables: &__SetResourcePermissionInput{ + Input: input, + }, + } + var err error + + var data SetResourcePermissionResponse + resp := &graphql.Response{Data: &data} + + err = client.MakeRequest( + ctx, + req, + resp, + ) + + return &data, err +} + func UpdateComplianceFramework( ctx context.Context, client graphql.Client, diff --git a/jupiterone/internal/client/genqlient.yaml b/jupiterone/internal/client/genqlient.yaml index 356433c0..2a831bb3 100644 --- a/jupiterone/internal/client/genqlient.yaml +++ b/jupiterone/internal/client/genqlient.yaml @@ -11,6 +11,7 @@ operations: - widget.graphql - dashboardParameter.graphql - integration.graphql + - resourcePermissions.graphql generated: generated.go bindings: diff --git a/jupiterone/internal/client/resourcePermissions.graphql b/jupiterone/internal/client/resourcePermissions.graphql new file mode 100644 index 00000000..393df3df --- /dev/null +++ b/jupiterone/internal/client/resourcePermissions.graphql @@ -0,0 +1,37 @@ +mutation SetResourcePermission($input: SetResourcePermissionInput!) { + setResourcePermission(input: $input) { + canCreate + canDelete + canRead + canUpdate + resourceArea + resourceId + resourceType + subjectId + subjectType + } +} + +mutation DeleteResourcePermission($input: DeleteResourcePermissionInput!) { + deleteResourcePermission(input: $input) { + success + } +} + +query GetResourcePermission( + $filter: GetResourcePermissionsFilter! + $cursor: String + $limit: Int +) { + getResourcePermissions(filter: $filter, cursor: $cursor, limit: $limit) { + canCreate + canDelete + canRead + canUpdate + resourceArea + resourceId + resourceType + subjectId + subjectType + } +} diff --git a/jupiterone/internal/client/rule.graphql b/jupiterone/internal/client/rule.graphql index f6570cd4..4af598d5 100644 --- a/jupiterone/internal/client/rule.graphql +++ b/jupiterone/internal/client/rule.graphql @@ -2,6 +2,7 @@ query GetQuestionRuleInstance($id: ID!) { questionRuleInstance(id: $id) { id name + collectionId description version specVersion @@ -33,6 +34,7 @@ query GetQuestionRuleInstance($id: ID!) { } # @genqlient(for: "RuleOperationInput.when", omitempty: true) +# @genqlient(for: "CreateInlineQuestionRuleInstanceInput.collectionId", omitempty: true) mutation CreateInlineQuestionRuleInstance( $instance: CreateInlineQuestionRuleInstanceInput! ) { @@ -63,6 +65,7 @@ mutation CreateInlineQuestionRuleInstance( } # @genqlient(for: "RuleOperationInput.when", omitempty: true) +# @genqlient(for: "CreateReferencedQuestionRuleInstanceInput.collectionId", omitempty: true) mutation CreateReferencedQuestionRuleInstance( $instance: CreateReferencedQuestionRuleInstanceInput! ) { @@ -88,6 +91,7 @@ mutation CreateReferencedQuestionRuleInstance( # @genqlient(for: "UpdateInlineQuestionRuleInstanceInput.outputs", omitempty: true) # @genqlient(for: "UpdateInlineQuestionRuleInstanceInput.state", omitempty: true) # @genqlient(for: "UpdateInlineQuestionRuleInstanceInput.remediationSteps", omitempty: true) +# @genqlient(for: "UpdateInlineQuestionRuleInstanceInput.collectionId", omitempty: true) mutation UpdateInlineQuestionRuleInstance( $instance: UpdateInlineQuestionRuleInstanceInput! ) { @@ -108,6 +112,7 @@ mutation UpdateInlineQuestionRuleInstance( # @genqlient(for: "UpdateReferencedQuestionRuleInstanceInput.outputs", omitempty: true) # @genqlient(for: "UpdateReferencedQuestionRuleInstanceInput.latestAlertId", omitempty: true) # @genqlient(for: "UpdateReferencedQuestionRuleInstanceInput.state", omitempty: true) +# @genqlient(for: "UpdateReferencedQuestionRuleInstanceInput.collectionId", omitempty: true) mutation UpdateReferencedQuestionRuleInstance( $instance: UpdateReferencedQuestionRuleInstanceInput! ) { diff --git a/jupiterone/provider.go b/jupiterone/provider.go index c6f67259..da66d042 100644 --- a/jupiterone/provider.go +++ b/jupiterone/provider.go @@ -143,6 +143,7 @@ func (*JupiterOneProvider) Resources(context.Context) []func() resource.Resource NewWidgetResource, NewDashboardParameterResource, NewIntegrationResource, + NewResourcePermissionResource, } } diff --git a/jupiterone/resource_resource_permission.go b/jupiterone/resource_resource_permission.go new file mode 100644 index 00000000..c1e14765 --- /dev/null +++ b/jupiterone/resource_resource_permission.go @@ -0,0 +1,227 @@ +package jupiterone + +import ( + "context" + "fmt" + + "github.com/Khan/genqlient/graphql" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/jupiterone/terraform-provider-jupiterone/jupiterone/internal/client" +) + +type ResourcePermissionResource struct { + version string + qlient graphql.Client +} + +type ResourcePermissionModel struct { + ID types.String `tfsdk:"id"` + SubjectType types.String `json:"subjectType" tfsdk:"subject_type"` + SubjectId types.String `json:"subjectId" tfsdk:"subject_id"` + ResourceArea types.String `json:"resourceArea" tfsdk:"resource_area"` + ResourceType types.String `json:"resourceType" tfsdk:"resource_type"` + ResourceId types.String `json:"resourceId" tfsdk:"resource_id"` + CanRead types.Bool `json:"canRead" tfsdk:"can_read"` + CanCreate types.Bool `json:"canCreate" tfsdk:"can_create"` + CanUpdate types.Bool `json:"canUpdate" tfsdk:"can_update"` + CanDelete types.Bool `json:"canDelete" tfsdk:"can_delete"` +} + +func NewResourcePermissionResource() resource.Resource { + return &ResourcePermissionResource{} +} + +func (*ResourcePermissionResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_resource_permission" +} + +func (r *ResourcePermissionResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + p, ok := req.ProviderData.(*JupiterOneProvider) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected JupiterOneProvider, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.version = p.version + r.qlient = p.Qlient +} + +func (*ResourcePermissionResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: "JupiterOne Resource Based Permission", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + }, + "subject_type": schema.StringAttribute{ + Required: true, + Description: "The type of the subject that the resource permissions will be applied to (e.g. group).", + }, + "subject_id": schema.StringAttribute{ + Required: true, + Description: "The ID of the subject that the resource permissions will be applied to (e.g. group ID).", + }, + "resource_area": schema.StringAttribute{ + Required: true, + Description: "The resource area that these permissions will be applied to (e.g. rule).", + }, + "resource_type": schema.StringAttribute{ + Required: true, + Description: "The resource type that these permissions will be applied to (e.g. rule, rule_collection, *).", + }, + "resource_id": schema.StringAttribute{ + Required: true, + Description: "The ID of the resource that these permissions will be applied to (e.g. rule ID, rule collection ID, *).", + }, + "can_read": schema.BoolAttribute{ + Required: true, + Description: "Whether the subject can read the resource.", + }, + "can_create": schema.BoolAttribute{ + Required: true, + Description: "Whether the subject can create the resource.", + }, + "can_update": schema.BoolAttribute{ + Required: true, + Description: "Whether the subject can update the resource.", + }, + "can_delete": schema.BoolAttribute{ + Required: true, + Description: "Whether the subject can delete the resource.", + }, + }, + } +} + +func (r *ResourcePermissionModel) BuildSetResourcePermissionInput() (client.SetResourcePermissionInput, error) { + permissionResource := client.SetResourcePermissionInput{ + SubjectType: r.SubjectType.ValueString(), + SubjectId: r.SubjectId.ValueString(), + ResourceArea: r.ResourceArea.ValueString(), + ResourceType: r.ResourceType.ValueString(), + ResourceId: r.ResourceId.ValueString(), + CanRead: r.CanRead.ValueBool(), + CanCreate: r.CanCreate.ValueBool(), + CanUpdate: r.CanUpdate.ValueBool(), + CanDelete: r.CanDelete.ValueBool(), + } + + return permissionResource, nil +} + +func (r *ResourcePermissionResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data *ResourcePermissionModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + permissionResource, err := data.BuildSetResourcePermissionInput() + + if err != nil { + resp.Diagnostics.AddError("failed to build resource permission from configuration", err.Error()) + return + } + + created, err := client.SetResourcePermission(ctx, r.qlient, permissionResource) + + if err != nil { + resp.Diagnostics.AddError("failed to create resource permission", err.Error()) + return + } + + data.ID = types.StringValue(fmt.Sprintf("%s-%s-%s-%s-%s", data.SubjectType.ValueString(), data.SubjectId.ValueString(), data.ResourceArea.ValueString(), data.ResourceType.ValueString(), data.ResourceId.ValueString())) + + tflog.Trace(ctx, "Set resource permission", + map[string]interface{}{"resourceArea": created.SetResourcePermission.ResourceArea}) + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +// Update and create are the same for this resource - just "set" the permission. But an update function is required for the resource interface. +func (r *ResourcePermissionResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data *ResourcePermissionModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + permissionResource, err := data.BuildSetResourcePermissionInput() + + if err != nil { + resp.Diagnostics.AddError("failed to build resource permission from configuration", err.Error()) + return + } + + created, err := client.SetResourcePermission(ctx, r.qlient, permissionResource) + + if err != nil { + resp.Diagnostics.AddError("failed to create resource permission", err.Error()) + return + } + + tflog.Trace(ctx, "Set resource permission", + map[string]interface{}{"resourceArea": created.SetResourcePermission.ResourceArea}) + + data.ID = types.StringValue(fmt.Sprintf("%s-%s-%s-%s-%s", data.SubjectType.ValueString(), data.SubjectId.ValueString(), data.ResourceArea.ValueString(), data.ResourceType.ValueString(), data.ResourceId.ValueString())) + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *ResourcePermissionResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data ResourcePermissionModel + + // Read Terraform state into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + var deleteInput client.DeleteResourcePermissionInput + deleteInput.SubjectType = data.SubjectType.ValueString() + deleteInput.SubjectId = data.SubjectId.ValueString() + deleteInput.ResourceArea = data.ResourceArea.ValueString() + deleteInput.ResourceType = data.ResourceType.ValueString() + deleteInput.ResourceId = data.ResourceId.ValueString() + + _, err := client.DeleteResourcePermission(ctx, r.qlient, deleteInput) + + if err != nil { + resp.Diagnostics.AddError("failed to delete resource permission", err.Error()) + return + } +} + +func (r *ResourcePermissionResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data *ResourcePermissionModel + + // Read Terraform state into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *ResourcePermissionResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} diff --git a/jupiterone/resource_resource_permission_test.go b/jupiterone/resource_resource_permission_test.go new file mode 100644 index 00000000..03b21cde --- /dev/null +++ b/jupiterone/resource_resource_permission_test.go @@ -0,0 +1,143 @@ +package jupiterone + +import ( + "context" + "fmt" + "strings" + "testing" + "time" + + "github.com/Khan/genqlient/graphql" + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/jupiterone/terraform-provider-jupiterone/jupiterone/internal/client" +) + +var resourceName = "jupiterone_resource_permission.test" +var subjectId = "example-group-id" + +func TestResourcePermission_Basic(t *testing.T) { + ctx := context.TODO() + + recordingClient, directClient, cleanup := setupTestClients(ctx, t) + defer cleanup(t) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories(recordingClient), + CheckDestroy: testAccCheckResourcePermissionDestroy(ctx, directClient), + Steps: []resource.TestStep{ + { + Config: testResourcePermissionConfig(subjectId, "group", "rule", "*", "*", true, true, true, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckResourcePermissionExists(ctx, directClient), + resource.TestCheckResourceAttr(resourceName, "subject_id", subjectId), + resource.TestCheckResourceAttr(resourceName, "subject_type", "group"), + resource.TestCheckResourceAttr(resourceName, "resource_area", "rule"), + resource.TestCheckResourceAttr(resourceName, "resource_type", "*"), + resource.TestCheckResourceAttr(resourceName, "resource_id", "*"), + resource.TestCheckResourceAttr(resourceName, "can_create", "true"), + resource.TestCheckResourceAttr(resourceName, "can_read", "true"), + resource.TestCheckResourceAttr(resourceName, "can_update", "true"), + resource.TestCheckResourceAttr(resourceName, "can_delete", "true"), + ), + }, + }, + }) +} + +func testAccCheckResourcePermissionExists(ctx context.Context, qlient graphql.Client) resource.TestCheckFunc { + return func(s *terraform.State) error { + if err := resourcePermissionExistsHelper(ctx, qlient); err != nil { + return err + } + return nil + } +} + +func resourcePermissionExistsHelper(ctx context.Context, qlient graphql.Client) error { + if qlient == nil { + return nil + } + + duration := 10 * time.Second + err2 := retry.RetryContext(ctx, duration, func() *retry.RetryError { + _, err := client.GetResourcePermission(ctx, qlient, client.GetResourcePermissionsFilter{SubjectId: "example-group-id", SubjectType: "group", ResourceArea: "rule", ResourceType: "*", ResourceId: "*"}, "", 10) + + if err == nil { + return nil + } + + if strings.Contains(err.Error(), "Cannot fetch resource permission that does not exist") { + return retry.RetryableError(fmt.Errorf("Resource permission does not exist")) + } + + return retry.NonRetryableError(err) + }) + + if err2 != nil { + return err2 + } + + return nil +} + +func testAccCheckResourcePermissionDestroy(ctx context.Context, qlient graphql.Client) func(*terraform.State) error { + return func(s *terraform.State) error { + resource := s.RootModule().Resources[resourceName] + if resource == nil { + hclog.Default().Debug("No resource found for permission name", "resource_name", resourceName) + return nil + } + hclog.Default().Debug("Attempting to delete resource for permission name", "resource_name", resourceName, "resource_id", resource.Primary.ID) + return resourcePermissionDestroyHelper(ctx, qlient) + } +} + +func resourcePermissionDestroyHelper(ctx context.Context, qlient graphql.Client) error { + if qlient == nil { + return nil + } + + duration := 10 * time.Second + err := retry.RetryContext(ctx, duration, func() *retry.RetryError { + _, err := client.GetResourcePermission(ctx, qlient, client.GetResourcePermissionsFilter{SubjectId: "example-group-id", SubjectType: "group", ResourceArea: "rule", ResourceType: "*", ResourceId: "*"}, "", 10) + + if err == nil { + return retry.RetryableError(fmt.Errorf("Permission set still exists")) + } + + if strings.Contains(err.Error(), "Rule instance does not exist.") { + return nil + } + + return retry.NonRetryableError(err) + }) + + if err != nil { + return err + } + + return nil +} + +func testResourcePermissionConfig(subjectId, subjectType, resourceArea, resourceType, resourceID string, canCreate, canRead, canUpdate, canDelete bool) string { + return fmt.Sprintf(` + provider "jupiterone" {} + + + resource "jupiterone_resource_permission" "test" { + subject_id = %q + subject_type = %q + resource_area = %q + resource_type = %q + resource_id = %q + can_create = %t + can_read = %t + can_update = %t + can_delete = %t + } + `, subjectId, subjectType, resourceArea, resourceType, resourceID, canCreate, canRead, canUpdate, canDelete) +} diff --git a/jupiterone/resource_rule.go b/jupiterone/resource_rule.go index 0380faa1..8c4c670c 100644 --- a/jupiterone/resource_rule.go +++ b/jupiterone/resource_rule.go @@ -127,6 +127,7 @@ type RuleModel struct { TriggerOnNewOnly types.Bool `json:"trigger_on_new_only" tfsdk:"trigger_on_new_only"` IgnorePreviousResults types.Bool `json:"ignore_previous_results" tfsdk:"ignore_previous_results"` Labels []RuleLabel `json:"labels" tfsdk:"labels"` + CollectionId types.String `json:"collection_id,omitempty" tfsdk:"collection_id"` } func NewQuestionRuleResource() resource.Resource { @@ -285,6 +286,10 @@ func (*QuestionRuleResource) Schema(ctx context.Context, req resource.SchemaRequ }, }, }, + "collection_id": schema.StringAttribute{ + Optional: true, + Description: "Specifies the ID of a collection for the rule to be added to", + }, }, // TODO: Deprecate the use of blocks following new framework guidance: // https://developer.hashicorp.com/terraform/plugin/framework/handling-data/blocks @@ -510,6 +515,12 @@ func (r *QuestionRuleResource) Read(ctx context.Context, req resource.ReadReques resp.Diagnostics.AddError("error unmarshaling templates from response", err.Error()) } + if rule.CollectionId != "" { + data.CollectionId = types.StringValue(rule.CollectionId) + } else { + data.CollectionId = types.StringNull() + } + if rule.QuestionId != "" { data.QuestionId = types.StringValue(rule.QuestionId) } else { @@ -647,6 +658,7 @@ func (r *RuleModel) BuildCreateReferencedQuestionRuleInstanceInput() (client.Cre NotifyOnFailure: r.NotifyOnFailure.ValueBool(), TriggerActionsOnNewEntitiesOnly: r.TriggerOnNewOnly.ValueBool(), IgnorePreviousResults: r.IgnorePreviousResults.ValueBool(), + CollectionId: r.CollectionId.ValueString(), } var err error @@ -696,6 +708,7 @@ func (r *RuleModel) BuildUpdateReferencedQuestionRuleInstanceInput() (client.Upd NotifyOnFailure: r.NotifyOnFailure.ValueBool(), TriggerActionsOnNewEntitiesOnly: r.TriggerOnNewOnly.ValueBool(), IgnorePreviousResults: r.IgnorePreviousResults.ValueBool(), + CollectionId: r.CollectionId.ValueString(), } var err error @@ -747,7 +760,7 @@ func (r *RuleModel) BuildCreateInlineQuestionRuleInstanceInput() (client.CreateI NotifyOnFailure: r.NotifyOnFailure.ValueBool(), TriggerActionsOnNewEntitiesOnly: r.TriggerOnNewOnly.ValueBool(), IgnorePreviousResults: r.IgnorePreviousResults.ValueBool(), - // Labels: r.Labels, + CollectionId: r.CollectionId.ValueString(), } var err error @@ -812,6 +825,7 @@ func (r *RuleModel) BuildUpdateInlineQuestionRuleInstanceInput() (client.UpdateI NotifyOnFailure: r.NotifyOnFailure.ValueBool(), TriggerActionsOnNewEntitiesOnly: r.TriggerOnNewOnly.ValueBool(), IgnorePreviousResults: r.IgnorePreviousResults.ValueBool(), + CollectionId: r.CollectionId.ValueString(), } var err error diff --git a/jupiterone/resource_rule_test.go b/jupiterone/resource_rule_test.go index cbee9572..79549b46 100644 --- a/jupiterone/resource_rule_test.go +++ b/jupiterone/resource_rule_test.go @@ -135,6 +135,7 @@ func TestInlineRuleInstance_BasicImport(t *testing.T) { resource.TestCheckResourceAttr(testRuleResourceName, "question.0.queries.0.query", "Find DataStore with classification=('critical' or 'sensitive' or 'confidential' or 'restricted') and encrypted!=true"), resource.TestCheckResourceAttr(testRuleResourceName, "labels.0.label_name", "label1"), resource.TestCheckResourceAttr(testRuleResourceName, "labels.#", "0"), + resource.TestCheckResourceAttr(testRuleResourceName, "collection_id", "null"), ), }, },