Repository: jfrog/terraform-provider-xray
Pull request #5 (2021-11-04 17:26:35)

Separate xray policies


Patch:
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 8a71c89b..242f92b4 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -12,7 +12,8 @@ A clear and concise description of what the bug is.
 
 **Requirements for and issue**
 - [ ] A fully functioning terraform snippet that can be copy&pasted (no outside files or ENV vars unless that's part of the issue)
-- [ ] Your version of artifactory (you can `curl` it at `$host/artifactory/api/system/version`
+- [ ] Your version of Artifactory and Xray (you can `curl` Artifactory version at `$host/artifactory/api/system/version` and Xray version at 
+`$host/xray/api/v1/system/version`
 - [ ] Your version of terraform
 
 **Expected behavior**
diff --git a/.gitignore b/.gitignore
index ff1e6f17..ef551798 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-terraform-provider-artifactory
+terraform-provider-xray
 dist/
 pkg/
 .idea/
diff --git a/GNUmakefile b/GNUmakefile
index bd150b23..4b20336b 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -39,7 +39,7 @@ attach:
 
 acceptance: fmtcheck
 	export TF_ACC=1
-	test -n ARTIFACTORY_USERNAME && test -n ARTIFACTORY_PASSWORD && test -n ARTIFACTORY_URL \
+	test -n ARTIFACTORY_USERNAME && test -n ARTIFACTORY_URL && test -n ARTIFACTORY_ACCESS_TOKEN \
 		&& go test -v -parallel 20 ./pkg/...
 
 
diff --git a/README.md b/README.md
index 6f3d2f6d..cf2385e6 100644
--- a/README.md
+++ b/README.md
@@ -1,201 +1,2 @@
-# Terraform Provider Artifactory
-
-[![Actions Status](https://github.com/jfrog/terraform-provider-artifactory/workflows/release/badge.svg)](https://github.com/jfrog/terraform-provider-artifactory/actions)
-[![Go Report Card](https://goreportcard.com/badge/github.com/jfrog/terraform-provider-artifactory)](https://goreportcard.com/report/github.com/jfrog/terraform-provider-artifactory)
-[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/jfrog/terraform)
-
-To use this provider in your Terraform module, follow the documentation [here](https://registry.terraform.io/providers/jfrog/artifactory/latest/docs).
-## Release notes for 2.3.1
-With the major version release of 2.3.1, all remnants of the original atlassian code have been pitched. A real effort 
-was made to sustain backward compatibility. For a variety of reasons, this was not possible. In some cases it simply
-couldn't be supported.
-
-In this release, all the rest clients were replaced with a single client: [Resty](https://github.com/go-resty/resty).
-The last major release before this major bump was 2.2.15, and it had no less than 4 different clients in use. In some
-cases, the jfrog-client-go code could have worked, but in others cases it was fundamentally incompatible with the way
-terraform needed to operate as the jfrog go client directly interpreted results as being errored or not (using non-standard
-error codes). In addition, the objective of this release is *not* to upgrade to new APIs, but to simply get rid of all the clients
-and get the tests passing. Since several of the V1 apis that this TF provider uses are not available in the jf-go client 
-this gave further reason to go it alone.
-
-The end result is much more transparent code and complete portability. The final approach taken was to use resty for all
-the calls and to manage authentication, but to use the jfg client for payload structure. In the case of xray, this was 
-not possible, and the original structure code was preserved. 
-
-## License requirements:
-
-This provider requires access to Artifactory APIs, which are only available in the _licensed_ pro and enterprise editions.
-You can determine which license you have by accessing the following URL
-`${host}/artifactory/api/system/licenses/`
-
-You can either access it via api, or web browser - it does require admin level credentials, but it's one of the few
-APIs that will work without a license (side node: you can also install your license here with a `POST`)
-```bash
-curl -sL ${host}/artifactory/api/system/licenses/ | jq .
-{
-  "type" : "Enterprise Plus Trial",
-  "validThrough" : "Jan 29, 2022",
-  "licensedTo" : "JFrog Ltd"
-}
-
-```
-The following 3 license types (`jq .type`) do **NOT** support APIs:
-- Community Edition for C/C++
-- JCR Edition
-- OSS
-
-## Limitations of functionality
-The current way a repository is created is essentially through a union of fields of certain repo types. 
-It's important to note that, the official documentation is used only for inspiration as the documentation is quite wrong.
-Support for some features has been achieved entirely through reverse engineering.
-
-### Local repository limitations
-[Local repository creation](https://www.jfrog.com/confluence/display/JFROG/Repository+Configuration+JSON#RepositoryConfigurationJSON-LocalRepository)
-does not support (directly), repository specific fields in all cases. It's basically a union of
-- Base repo params
-- Maven
-- Gradle
-- Debian
-- Docker (v1)
-- RPM
-
-### Remote repository limitations
-[Remote repository creation](https://www.jfrog.com/confluence/display/JFROG/Repository+Configuration+JSON#RepositoryConfigurationJSON-RemoteRepository) 
-does not support (directly), repository specific fields in all cases. It's basically a union of
-- base remote repo params
-- bower support
-- maven
-- gradle
-- Docker (v1)
-- VCS
-- Pypi
-- Nuget 
-Query params may be forwarded, but this field doesn't exist in the documentation
-
-### Permission target limitations
-[Permission target V2](https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-CreateorReplacePermissionTarget)
-Permission target V1 support has been totally removed. Dynamically testing of permission targets using a new repository
-currently doesn't work because of race conditions when creating a repo. This will have to be resolved with retries at a 
-later date. 
-
-### Changes to user creation ###
-Previously, passwords were being generated for the user if none was supplied. This was both unnecessary (since TF has a password provider)
-and because the internal implementation could never be entirely in line with the remote server (or, be sure it was).
-With the release of 2.3.1, password is still optional, but if supplied, must watch the default password requirements. These
-can be overridden with `JFROG_PASSWD_VALIDATION_ON=false` if a custom password policy is in place.
-
-
-## Build the Provider
-Simply run `make install` - this will compile the provider and install it to `~/.terraform.d`. When running this, it will
-take the current tag and bump it 1 minor version. It does not actually create a new tag (that is `make release`). 
-If you wish to use the locally installed provider, make sure your TF script refers to the new version number 
-
-Requirements:
-- [Terraform](https://www.terraform.io/downloads.html) 0.13
-- [Go](https://golang.org/doc/install) 1.15+ (to build the provider plugin)
-
-## Testing
-How to run the tests isn't obvious.
-First, you need a running instance of the jfrog platform (RT and XR). However, there is no currently supported dockerized, local
-version. You can ask for an instance to test against in as part of your PR or by messaging the maintainer in gitter
-Alternatively, you can run the file [scripts/run-artifactory.sh](scripts/run-artifactory.sh), which, if have a file in the same
-directory called `artifactory.lic`, you can start just an artifactory instance. The license, however, is not supplied
-
-Once you have that done you must set the following properties
-
-Then, you have to set some environment variables as this is how the acceptance tests pick up their config
-```bash
-ARTIFACTORY_URL=http://localhost:8082
-ARTIFACTORY_USERNAME=admin
-ARTIFACTORY_PASSWORD=password
-TF_ACC=FOO
-```
-a crucial, and very much hidden, env var to set is
-`TF_ACC=FOO` - you can literally set `TF_ACC` to anything you want, so long as it's set. The acceptance tests use
-terraform testing libraries that, if this flag isn't set, will skip all tests.
-
-You can then run the tests as
-`go test -v ./pkg/...`
-**DO NOT** remove the `-v` - terraform testing needs this (don't ask me why). This will recursively run all tests, including
-acceptance tests. 
-
-## Debugging
-Debugging a terraform provider is not straightforward. Terraform forks your provider as a separate process and then 
-connects to it via RPC. Normally, when debugging, you would start the process to debug directly. However, with the 
-terraform + go architecture, this isn't possible. So, you need to run terraform as you normally would and attach to the
-provider process by getting it's pid. This would be really tricky considering how fast the process can come up and be down.
-So, you need to actually halt the provider and have it wait for your debugger to attach. 
-
-Having said all that, here are the steps:
-1. Install [delve](https://github.com/go-delve/delve)
-2. Keep in mind that terraform will 
-   parallel process if it can, and it will start new instances of the TF provider process when running apply between the plan and confirmation
-   Add a snippet of go code to the close to where you need to break where in you install a busy sleep loop:
-```go
-	debug := true
-	for debug {
-		time.Sleep(time.Second) // set breakpoint here
-	}
-``` 
-Then set a breakpoint inside the loop. Once you have attached to the process you can set the `debug` value to `false`,
-thus breaking the sleep loop and allow you to continue. 
-2. Compile the provider with debug symbology (`go build -gcflags "all=-N -l"`)
-3. Install the provider (change as needed for your version)
-```bash 
-# this will bump your version by 1 so it doesn't download from TF. Make sure you update any test scripts accordingly
-make install 
-```
-4. Run your provider: `terraform init && terraform plan` - it will start in this busy sleep loop.
-5. In a separate shell, find the `PID` of the provider that got forked 
-`pgrep terraform-provider-artifactory`
-6. Then, attach the debugger to that pid: `dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient attach $pid`
-A 1-liner for this whole process is: 
-`dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient attach $(pgrep terraform-provider-artifactory)`
-7. In intellij, setup a remote go debugging session (the default port is `2345`, but make sure it's set.) And click the `debug` button
-8. Your editor should immediately break at the breakpoint from step 2. At this point, in the watch window, edit the `debug` 
-value and set it to false, and allow the debugger to continue. Be ready for your debugging as this will release the provider 
-and continue executing normally.
-
-You will need to repeat steps 4-8 everytime you want to debug
-
-
-
-
-
-## Versioning
-In general, this project follows [semver](https://semver.org/) as closely as we
-can for tagging releases of the package. We've adopted the following versioning policy:
-
-* We increment the **major version** with any incompatible change to
-	functionality, including changes to the exported Go API surface
-	or behavior of the API.
-* We increment the **minor version** with any backwards-compatible changes to
-	functionality.
-* We increment the **patch version** with any backwards-compatible bug fixes.
-
-## Contributors
-Pull requests, issues and comments are welcomed. For pull requests:
-
-* Add tests for new features and bug fixes
-* Follow the existing style
-* Separate unrelated changes into multiple pull requests
-
-See the existing issues for things to start contributing.
-
-For bigger changes, make sure you start a discussion first by creating
-an issue and explaining the intended change.
-
-JFrog requires contributors to sign a Contributor License Agreement,
-known as a CLA. This serves as a record stating that the contributor is
-entitled to contribute the code/documentation/translation to the project
-and is willing to have it used in distributions and derivative works
-(or is willing to transfer ownership).
-
-[Sign the CLA](https://cla-assistant.io/jfrog/terraform-provider-artifactory)
-
-## License
-Copyright (c) 2020 JFrog.
-
-Apache 2.0 licensed, see [LICENSE][LICENSE] file.
-
-[LICENSE]: ./LICENSE
\ No newline at end of file
+# Terraform Provider Xray
+[Xray API Documentation](https://www.jfrog.com/confluence/display/JFROG/Xray+REST+API)
\ No newline at end of file
diff --git a/docs/data-sources/artifactory_file.md b/docs/data-sources/artifactory_file.md
deleted file mode 100644
index e604ca8e..00000000
--- a/docs/data-sources/artifactory_file.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# Artifactory File Data Source
-
-Provides an Artifactory file datasource. This can be used to download a file from a given Artifactory repository.
-
-## Example Usage
-
-```hcl
-# 
-data "artifactory_file" "my-file" {
-   repository = "repo-key"
-   path = "/path/to/the/artifact.zip"
-   output_path = "tmp/artifact.zip"
-}
-```
-
-## Argument Reference
-
-The following arguments are supported:
-
-* `repository` - (Required) Name of the repository where the file is stored.
-* `path` - (Required) The path to the file within the repository.
-* `output_path` - (Required) The local path the file should be downloaded to.
-* `force_overwrite` - (Optional) If set to true, an existing file in the output_path will be overwritten. Default: false
-
-## Attribute Reference
-
-In addition to all arguments above, the following attributes are exported:
-
-* `created` - The time & date when the file was created.
-* `created_by` - The user who created the file.
-* `last_modified` - The time & date when the file was last modified.
-* `modified_by` - The user who last modified the file.
-* `last_updated` - The time & date when the file was last updated.
-* `mimetype` - The mimetype of the file.
-* `size` - The size of the file.
-* `download_uri` - The URI that can be used to download the file.
-* `md5` - MD5 checksum of the file.
-* `sha1` - SHA1 checksum of the file.
-* `sha256` - SHA256 checksum of the file.
diff --git a/docs/data-sources/artifactory_fileinfo.md b/docs/data-sources/artifactory_fileinfo.md
deleted file mode 100644
index a581b083..00000000
--- a/docs/data-sources/artifactory_fileinfo.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# Artifactory File Info Data Source
-
-Provides an Artifactory fileinfo datasource. This can be used to read metadata of files stored in Artifactory repositories.
-
-## Example Usage
-
-```hcl
-# 
-data "artifactory_fileinfo" "my-file" {
-   repository = "repo-key"
-   path = "/path/to/the/artifact.zip" 
-}
-```
-
-## Argument Reference
-
-The following arguments are supported:
-
-* `repository` - (Required) Name of the repository where the file is stored.
-* `path` - (Required) The path to the file within the repository.
-
-## Attribute Reference
-
-In addition to all arguments above, the following attributes are exported:
-
-* `created` - The time & date when the file was created.
-* `created_by` - The user who created the file.
-* `last_modified` - The time & date when the file was last modified.
-* `modified_by` - The user who last modified the file.
-* `last_updated` - The time & date when the file was last updated.
-* `mimetype` - The mimetype of the file.
-* `size` - The size of the file.
-* `download_uri` - The URI that can be used to download the file.
-* `md5` - MD5 checksum of the file.
-* `sha1` - SHA1 checksum of the file.
-* `sha256` - SHA256 checksum of the file.
diff --git a/docs/debug.md b/docs/debug.md
index 9e750456..1264b390 100644
--- a/docs/debug.md
+++ b/docs/debug.md
@@ -43,9 +43,9 @@ This code effectively creates an infinite sleep loop; but that's actually essent
 terraform will basically stop, as it waits on a response from you provider; because you put an infinite sleep loop in
 5. You must now tell `delve` to connect to this remote process using it's PID. This isn't as hard as it seems.
 Run this commands:
-`dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient attach $(pgrep terraform-provider-artifactory)`
+`dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient attach $(pgrep terraform-provider-xray)`
 The last argument gets the `PID` for your provider and supplies it to `delve` to connect. Immediately upon running this 
-command, you're going to hit your break point. Please make sure to substitute `terraform-provider-artifactory` for your provider name
+command, you're going to hit your break point. Please make sure to substitute `terraform-provider-xray` for your provider name
 6. To exit this infinite loop, use your debugger to set `connected` to `true`. By doing so you change the loop predicate 
 and it will exit this loop on the next iteration.
 7. *DEBUG!* - At this point you can, step, watch, drop the call stack, etc. Your whole arsenel is available
diff --git a/docs/index.md b/docs/index.md
index 06f0a4a1..63299149 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,119 +1,1 @@
-# Artifactory Provider
-
-The [Artifactory](https://jfrog.com/artifactory/) provider is used to interact with the
-resources supported by Artifactory. The provider needs to be configured
-with the proper credentials before it can be used.
-
-Links to documentation for specific resources can be found in the table of
-contents to the left.
-
-This provider requires access to Artifactory APIs, which are only available in the _licensed_ pro and enterprise editions.
-You can determine which license you have by accessing the following URL
-`${host}/artifactory/api/system/licenses/`
-
-You can either access it via api, or web browser - it does require admin level credentials, but it's one of the few
-APIs that will work without a license (side node: you can also install your license here with a `POST`)
-
-```bash
-curl -sL ${host}/artifactory/api/system/licenses/ | jq .
-{
-  "type" : "Enterprise Plus Trial",
-  "validThrough" : "Jan 29, 2022",
-  "licensedTo" : "JFrog Ltd"
-}
-
-```
-
-The following 3 license types (`jq .type`) do **NOT** support APIs:
-- Community Edition for C/C++
-- JCR Edition
-- OSS
-
-## Example Usage
-```hcl
-# Required for Terraform 0.13 and up (https://www.terraform.io/upgrade-guides/0-13.html)
-terraform {
-  required_providers {
-    artifactory = {
-      source  = "registry.terraform.io/jfrog/artifactory"
-      version = "2.2.7"
-    }
-  }
-}
-
-# Configure the Artifactory provider
-provider "artifactory" {
-  url = "${var.artifactory_url}/artifactory"
-  username = "${var.artifactory_username}"
-  password = "${var.artifactory_password}"
-}
-
-# Create a new repository
-resource "artifactory_local_repository" "pypi-libs" {
-  key             = "pypi-libs"
-  package_type    = "pypi"
-  repo_layout_ref = "simple-default"
-  description     = "A pypi repository for python packages"
-}
-```
-
-## Authentication
-The Artifactory provider supports multiple means of authentication. The following methods are supported:
-
-    * Basic Auth
-    * Bearer Token
-    * JFrog API Key Header
-
-### Basic Auth
-Basic auth may be used by adding a `username` and `password` field to the provider block
-Getting this value from the environment is supported with the `ARTIFACTORY_USERNAME` and `ARITFACTORY_PASSWORD` variable
-
-Usage:
-```hcl
-# Configure the Artifactory provider
-provider "artifactory" {
-  url = "artifactory.site.com/artifactory"
-  username = "myusername"
-  password = "mypassword"
-}
-```
-
-### Bearer Token
-Artifactory access tokens may be used via the Authorization header by providing the `access_token` field to the provider
-block. Getting this value from the environment is supported with the `ARTIFACTORY_ACCESS_TOKEN` variable
-
-Usage:
-```hcl
-# Configure the Artifactory provider
-provider "artifactory" {
-  url = "artifactory.site.com/artifactory"
-  access_token = "abc...xy"
-}
-```
-
-### JFrog API Key Header
-Artifactory API keys may be used via the `X-JFrog-Art-Api` header by providing the `api_key` field in the provider block.
-Getting this value from the environment is supported with the `ARTIFACTORY_API_KEY` variable
-
-Usage:
-```hcl
-# Configure the Artifactory provider
-provider "artifactory" {
-  url = "artifactory.site.com/artifactory"
-  api_key = "abc...xy"
-}
-```
-
-## Argument Reference
-
-The following arguments are supported:
-
-* `url` - (Required) URL of Artifactory. This can also be sourced from the `ARTIFACTORY_URL` environment variable.
-* `username` - (Optional) Username for basic auth. Requires `password` to be set. 
-    Conflicts with `api_key`, and `access_token`. This can also be sourced from the `ARTIFACTORY_USERNAME` environment variable.
-* `password` - (Optional) Password for basic auth. Requires `username` to be set. 
-    Conflicts with `api_key`, and `access_token`. This can also be sourced from the `ARTIFACTORY_PASSWORD` environment variable.
-* `api_key` - (Optional) API key for api auth. Uses `X-JFrog-Art-Api` header. 
-    Conflicts with `username`, `password`, and `access_token`. This can also be sourced from the `ARTIFACTORY_API_KEY` environment variable.
-* `access_token` - (Optional) API key for token auth. Uses `Authorization: Bearer` header. For xray functionality, this is the only auth method accepted
-    Conflicts with `username` and `password`, and `api_key`. This can also be sourced from the `ARTIFACTORY_ACCESS_TOKEN` environment variable.
+# JFrog Xray Provider
diff --git a/docs/resources/artifactory_access_token.md b/docs/resources/artifactory_access_token.md
index f43ee9ab..e69de29b 100644
--- a/docs/resources/artifactory_access_token.md
+++ b/docs/resources/artifactory_access_token.md
@@ -1,194 +0,0 @@
-# Artifactory Access Token Resource
-
-Provides an Artifactory Access Token resource. This can be used to create and manage Artifactory Access Tokens.
-
-~> **Note:** Access Tokens will be stored in the raw state as plain-text. [Read more about sensitive data in
-state](https://www.terraform.io/docs/state/sensitive-data.html).
-
-
-## Example Usages
-### Create a new Artifactory Access Token for an existing user
-
-```hcl
-resource "artifactory_access_token" "exising_user" {
-  username          = "existing-user"
-  end_date_relative = "5m"
-}
-```
-
-Note: This assumes that the user `existing-user` has already been created in Artifactory by different means, i.e. manually or in a separate terraform apply.
-
-### Create a new Artifactory User and Access token
-```hcl
-resource "artifactory_user" "new_user" {
-  name   = "new_user"
-  email  = "new_user@somewhere.com"
-
-  groups = [
-    "readers",
-  ]
-}
-
-resource "artifactory_access_token" "new_user" {
-  username          = artifactory_user.new_user.name
-  end_date_relative = "5m"
-}
-```
-
-### Creates a new token for groups
-This creates a transient user called `temporary-user`.
-```hcl
-resource "artifactory_access_token" "temporary_user" {
-  username          = "temporary-user"
-  end_date_relative = "1h"
-
-  groups = [
-    "readers",
-  ]
-}
-```
-
-### Create token with no expiry
-```hcl
-resource "artifactory_access_token" "no_expiry" {
-  username          = "existing-user"
-  end_date_relative = "0s"
-}
-```
-
-### Creates a refreshable token
-```hcl
-resource "artifactory_access_token" "refreshable" {
-  username          = "refreshable"
-  end_date_relative = "1m"
-
-  refreshable = true
-
-  groups = [
-    "readers",
-  ]
-}
-```
-
-### Creates an administrator token
-```hcl
-resource "artifactory_access_token" "admin" {
-  username          = "admin"
-  end_date_relative = "1m"
-
-  admin_token {
-    instance_id = "<instance id>"
-  }
-}
-```
-
-### Creates a token with an audience
-```hcl
-resource "artifactory_access_token" "audience" {
-  username          = "audience"
-  end_date_relative = "1m"
-
-  audience = "jfrt@*"
-  refreshable = true
-}
-```
-
-### Creates a token with a fixed end date
-```hcl
-resource "artifactory_access_token" "fixeddate" {
-  username = "fixeddate"
-  end_date = "2018-01-01T01:02:03Z"
-
-  groups = [
-    "readers",
-  ]
-}
-```
-
-### Rotate token after it expires
-This example will generate a token that will expire in 1 hour.
-
-If `terraform apply` is run before 1 hour, nothing changes.
-One an hour has passed, `terraform apply` will generate a new token.
-
-```hcl
-resource "time_rotating" "now_plus_1_hours" {
-  rotation_hours = "1"
-}
-
-resource "artifactory_access_token" "rotating" {
-  username = "rotating"
-
-  # the end_date is set to now + 1 hours
-  end_date = time_rotating.now_plus_1_hour.rotation_rfc3339
-
-  groups = [
-    "readers",
-  ]
-}
-```
-
-### Rotate token each terraform apply
-This example will generate a token that will expire in 1 hour.
-
-If `terraform apply` is run before 1 hour, a new token is generated with an expiry of 1 hour.
-
-```hcl
-resource "time_rotating" "now_plus_1_hours" {
-  triggers = {
-    "key" = timestamp()
-  }
-
-  rotation_hours = "1"
-}
-
-resource "artifactory_access_token" "rotating" {
-  username = "rotating"
-
-  # the end_date is set to now + 1 hours
-  end_date = time_rotating.now_plus_1_hour.rotation_rfc3339
-
-  groups = [
-    "readers",
-  ]
-}
-```
-
-## Attribute Reference
-
-The following arguments are supported:
-
-* `username` - (Required) The username or subject for the token. A non-admin can only specify their own username. Admins can specify any existing username, or a new name for a temporary token. Temporary tokens require `groups` to be set.
-
-* One of `end_date` or `end_date_relative` must be set.
-
-    * `end_date` - (Optional) The end date which the token is valid until, formatted as a RFC3339 date string (e.g. `2018-01-01T01:02:03Z`).
-
-    * `end_date_relative` - (Optional) A relative duration for which the token is valid until, for example `240h` (10 days) or `2400h30m`. Valid time units are "s", "m", "h".
-
-* `groups` - (Optional) List of groups. The token is granted access based on the permissions of the groups. Specify `["*"]` for all groups that the user belongs to. `groups` cannot be specified with `admin_token`.
-* `admin_token` - (Optional) Specify the `instance_id` in this block to grant this token admin privileges. This can only be created when the authenticated user is an admin. `admin_token` cannot be specified with `groups`.
-* `refreshable` - (Optional) Is this token refreshable? Defaults to `false`
-* `audience` - (Optional) A space-separate list of the other Artifactory instances or services that should accept this token identified by their Artifactory Service IDs. You may set `"jfrt@*"` so the token to be accepted by all Artifactory instances.
-
-  Refreshable must be `true` to set the `audience`. 
-    
-    For instructions to retrieve the Artifactory Service ID see this [documentation](https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-GetServiceID).
-
-**Notes:**
-- Changing **any** field forces a new resource to be created.
-- Although you can create a refreshable token, by setting `refreshable` to true, the resource does **not** implement a token refresh on subsequent executions of Terraform.
-
-The following additional attributes are exported:
-
-* `access_token` - Returns the access token to authenciate to Artifactory
-* `refresh_token` - Returns the refresh token when `refreshable` is true, or an empty string when `refreshable` is false
-
-## References
-
-- https://www.jfrog.com/confluence/display/ACC1X/Access+Tokens
-- https://www.jfrog.com/confluence/display/JFROG/Artifactory+REST+API#ArtifactoryRESTAPI-CreateToken
-
-## Import
-
-Artifactory **does not** retain access tokens and cannot be imported into state.
diff --git a/go.mod b/go.mod
index 964133e5..c82abd47 100644
--- a/go.mod
+++ b/go.mod
@@ -1,5 +1,4 @@
-//module github.com/jfrog/terraform-provider-xray
-module terraform-provider-xray
+module github.com/jfrog/terraform-provider-xray
 
 require (
 	github.com/go-resty/resty/v2 v2.6.1-0.20210916045937-1792d629c3c6
diff --git a/main.go b/main.go
index d674455f..b3acb4f3 100644
--- a/main.go
+++ b/main.go
@@ -2,8 +2,7 @@ package main
 
 import (
 	"github.com/hashicorp/terraform-plugin-sdk/v2/plugin"
-	//"github.com/jfrog/terraform-provider-xray/pkg/xray"
-	"terraform-provider-xray/pkg/xray"
+	"github.com/jfrog/terraform-provider-xray/pkg/xray"
 )
 
 func main() {
diff --git a/pkg/xray/policies.go b/pkg/xray/policies.go
new file mode 100644
index 00000000..624652bf
--- /dev/null
+++ b/pkg/xray/policies.go
@@ -0,0 +1,477 @@
+package xray
+
+import (
+	"context"
+	"github.com/go-resty/resty/v2"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+	"log"
+	"net/http"
+)
+
+// PolicyCVSSRange All of this was ripped out of it's original location and copied here.
+// The original provider code used th v1 API, which is not supported in the JFROG go client
+// The current objective is to rip out any dependencies not from jfrog. So, jfrog doesn't support it
+// I need backward compatibility, and I can't have any other dependencies.
+
+type PolicyCVSSRange struct {
+	To   float64 `json:"to,omitempty"`
+	From float64 `json:"from,omitempty"`
+}
+
+type PolicyRuleCriteria struct {
+	// Security Criteria
+	MinimumSeverity string           `json:"min_severity,omitempty"`
+	CVSSRange       *PolicyCVSSRange `json:"cvss_range,omitempty"`
+
+	// License Criteria
+	AllowUnknown           *bool     `json:"allow_unknown,omitempty"`
+	MultiLicensePermissive *bool     `json:"multi_license_permissive,omitempty"`
+	BannedLicenses         *[]string `json:"banned_licenses,omitempty"`
+	AllowedLicenses        *[]string `json:"allowed_licenses,omitempty"`
+}
+
+type BlockDownloadSettings struct {
+	Unscanned *bool `json:"unscanned,omitempty"`
+	Active    *bool `json:"active,omitempty"`
+}
+
+type PolicyRuleActions struct {
+	Webhooks                *[]string              `json:"webhooks,omitempty"`
+	Mails                   *[]string              `json:"mails,omitempty"`
+	FailBuild               *bool                  `json:"fail_build,omitempty"`
+	BlockDownload           *BlockDownloadSettings `json:"block_download,omitempty"`
+	BlockReleaseBundle      *bool                  `json:"block_release_bundle_distribution,omitempty"`
+	NotifyWatchRecipients   *bool                  `json:"notify_watch_recipients,omitempty"`
+	NotifyDeployer          *bool                  `json:"notify_deployer,omitempty"`
+	CreateJiraTicketEnabled *bool                  `json:"create_ticket_enabled,omitempty"`
+	FailureGracePeriodDays  *int                   `json:"build_failure_grace_period_in_days,omitempty"`
+	// License Actions
+	CustomSeverity *string `json:"custom_severity,omitempty"`
+}
+
+type PolicyRule struct {
+	Name     *string             `json:"name,omitempty"`
+	Priority *int                `json:"priority,omitempty"`
+	Criteria *PolicyRuleCriteria `json:"criteria,omitempty"`
+	Actions  *PolicyRuleActions  `json:"actions,omitempty"`
+}
+
+type Policy struct {
+	Name        *string       `json:"name,omitempty"`
+	Type        *string       `json:"type,omitempty"`
+	Author      *string       `json:"author,omitempty"`
+	Description *string       `json:"description,omitempty"`
+	Rules       *[]PolicyRule `json:"rules,omitempty"`
+	Created     *string       `json:"created,omitempty"`
+	Modified    *string       `json:"modified,omitempty"`
+}
+
+func expandPolicy(d *schema.ResourceData) (*Policy, error) {
+	policy := new(Policy)
+
+	policy.Name = StringPtr(d.Get("name").(string))
+	if v, ok := d.GetOk("type"); ok {
+		policy.Type = StringPtr(v.(string))
+	}
+	if v, ok := d.GetOk("description"); ok {
+		policy.Description = StringPtr(v.(string))
+	}
+	if v, ok := d.GetOk("author"); ok {
+		policy.Author = StringPtr(v.(string))
+	}
+	policyRules, err := expandRules(d.Get("rules").([]interface{}), policy.Type)
+	policy.Rules = &policyRules
+
+	return policy, err
+}
+
+func expandRules(configured []interface{}, policyType *string) (policyRules []PolicyRule, err error) {
+	rules := make([]PolicyRule, 0, len(configured))
+
+	for _, raw := range configured {
+		rule := new(PolicyRule)
+		data := raw.(map[string]interface{})
+		rule.Name = StringPtr(data["name"].(string))
+		rule.Priority = IntPtr(data["priority"].(int))
+		if *policyType == "license" {
+			rule.Criteria, err = expandLicenseCriteria(data["criteria"].([]interface{}))
+		}
+		if *policyType == "security" {
+			rule.Criteria, err = expandSecurityCriteria(data["criteria"].([]interface{}))
+		}
+
+		if v, ok := data["actions"]; ok {
+			rule.Actions = expandActions(v.([]interface{}))
+		}
+		rules = append(rules, *rule)
+	}
+
+	return rules, err
+}
+
+func expandLicenseCriteria(l []interface{}) (*PolicyRuleCriteria, error) {
+	if len(l) == 0 {
+		return nil, nil
+	}
+	m := l[0].(map[string]interface{}) // We made this a list of one to make schema validation easier
+	criteria := new(PolicyRuleCriteria)
+	if (m["allow_unknown"]) != nil {
+		criteria.AllowUnknown = BoolPtr(m["allow_unknown"].(bool))
+	}
+	if (m["banned_licenses"]) != nil {
+		criteria.BannedLicenses = expandLicenses(m["banned_licenses"].([]interface{}))
+	}
+	if (m["allowed_licenses"]) != nil {
+		criteria.AllowedLicenses = expandLicenses(m["allowed_licenses"].([]interface{}))
+	}
+	if (m["multi_license_permissive"]) != nil {
+		criteria.MultiLicensePermissive = BoolPtr(m["multi_license_permissive"].(bool))
+	}
+
+	return criteria, nil
+}
+
+func expandSecurityCriteria(l []interface{}) (*PolicyRuleCriteria, error) {
+	if len(l) == 0 {
+		return nil, nil
+	}
+	m := l[0].(map[string]interface{}) // We made this a list of one to make schema validation easier
+	criteria := new(PolicyRuleCriteria)
+
+	if (m["min_severity"]) != nil {
+		criteria.MinimumSeverity = m["min_severity"].(string)
+	}
+	if (m["cvss_range"]) != nil {
+		criteria.CVSSRange = expandCVSSRange(m["cvss_range"].([]interface{}))
+	}
+	return criteria, nil
+}
+
+func expandCVSSRange(l []interface{}) *PolicyCVSSRange {
+	if len(l) == 0 {
+		return nil
+	}
+
+	m := l[0].(map[string]interface{})
+	cvssrange := &PolicyCVSSRange{
+		From: m["from"].(float64),
+		To:   m["to"].(float64),
+	}
+	return cvssrange
+}
+
+func expandLicenses(l []interface{}) *[]string {
+	if len(l) == 0 {
+		return nil
+	}
+
+	licenses := make([]string, 0, len(l))
+	for _, license := range l {
+		licenses = append(licenses, license.(string))
+	}
+	return &licenses
+}
+
+func expandActions(l []interface{}) *PolicyRuleActions {
+	if len(l) == 0 {
+		return nil
+	}
+
+	actions := new(PolicyRuleActions)
+	m := l[0].(map[string]interface{}) // We made this a list of one to make schema validation easier
+	if v, ok := m["webhooks"]; ok && len(v.([]interface{})) > 0 {
+		m := v.([]interface{})
+		webhooks := make([]string, 0, len(m))
+		for _, hook := range m {
+			webhooks = append(webhooks, hook.(string))
+		}
+		actions.Webhooks = &webhooks // if webhook in not set - the empty value is not passing to the payload
+	}
+	if v, ok := m["mails"]; ok && len(v.([]interface{})) > 0 {
+		m := v.([]interface{})
+		mails := make([]string, 0, len(m))
+		for _, mail := range m {
+			mails = append(mails, mail.(string))
+		}
+		actions.Mails = &mails
+	}
+	if v, ok := m["fail_build"]; ok {
+		actions.FailBuild = BoolPtr(v.(bool))
+	}
+
+	if v, ok := m["block_download"]; ok {
+		if len(v.([]interface{})) > 0 {
+			vList := v.([]interface{})
+			vMap := vList[0].(map[string]interface{})
+
+			actions.BlockDownload = &BlockDownloadSettings{
+				Unscanned: BoolPtr(vMap["unscanned"].(bool)),
+				Active:    BoolPtr(vMap["active"].(bool)),
+			}
+		} else {
+			actions.BlockDownload = &BlockDownloadSettings{
+				Unscanned: BoolPtr(false),
+				Active:    BoolPtr(false),
+			}
+			// Setting this false/false block feels like it _should_ work, since putting a false/false block in the terraform resource works fine
+			// However, it doesn't, and we end up getting this diff when running acceptance tests when this is optional in the schema
+			// rules.0.actions.0.block_download.#:           "1" => "0"
+			// rules.0.actions.0.block_download.0.active:    "false" => ""
+			// rules.0.actions.0.block_download.0.unscanned: "false" => ""
+		}
+	}
+	if v, ok := m["block_release_bundle_distribution"]; ok {
+		actions.BlockReleaseBundle = BoolPtr(v.(bool)) // TODO: why do we need to return the poiner instead of just assigning the value?
+	}
+	//
+	if v, ok := m["notify_watch_recipients"]; ok {
+		actions.NotifyWatchRecipients = BoolPtr(v.(bool))
+	}
+	if v, ok := m["block_release_bundle_distribution"]; ok {
+		actions.BlockReleaseBundle = BoolPtr(v.(bool))
+	}
+	if v, ok := m["notify_deployer"]; ok {
+		actions.NotifyDeployer = BoolPtr(v.(bool))
+	}
+	if v, ok := m["create_ticket_enabled"]; ok {
+		actions.CreateJiraTicketEnabled = BoolPtr(v.(bool))
+	}
+	if v, ok := m["build_failure_grace_period_in_days"]; ok {
+		actions.FailureGracePeriodDays = IntPtr(v.(int))
+	}
+	if v, ok := m["custom_severity"]; ok {
+		gosucks := v.(string)
+		actions.CustomSeverity = &gosucks
+	}
+
+	return actions
+}
+
+func flattenLicenseRules(rules []PolicyRule) []interface{} {
+	l := make([]interface{}, len(rules))
+
+	for i, rule := range rules {
+		m := map[string]interface{}{
+			"name":     *rule.Name,
+			"priority": *rule.Priority,
+			"criteria": flattenLicenseCriteria(rule.Criteria),
+			"actions":  flattenActions(rule.Actions),
+		}
+		l[i] = m
+	}
+
+	return l
+}
+
+func flattenSecurityRules(rules []PolicyRule) []interface{} {
+	l := make([]interface{}, len(rules))
+
+	for i, rule := range rules {
+		m := map[string]interface{}{
+			"name":     *rule.Name,
+			"priority": *rule.Priority,
+			"criteria": flattenSecurityCriteria(rule.Criteria),
+			"actions":  flattenActions(rule.Actions),
+		}
+		l[i] = m
+	}
+
+	return l
+}
+
+func flattenLicenseCriteria(criteria *PolicyRuleCriteria) []interface{} {
+	if criteria == nil {
+		return []interface{}{}
+	}
+	m := map[string]interface{}{}
+
+	if criteria.BannedLicenses != nil {
+		m["banned_licenses"] = *criteria.BannedLicenses
+	}
+	if criteria.AllowedLicenses != nil {
+		m["allowed_licenses"] = *criteria.AllowedLicenses
+	}
+	if criteria.AllowUnknown != nil {
+		m["allow_unknown"] = *criteria.AllowUnknown // Same typo in the library
+	}
+	if criteria.MultiLicensePermissive != nil {
+		m["multi_license_permissive"] = *criteria.MultiLicensePermissive
+	}
+
+	return []interface{}{m}
+}
+
+func flattenSecurityCriteria(criteria *PolicyRuleCriteria) []interface{} {
+	if criteria == nil {
+		return []interface{}{}
+	}
+	m := map[string]interface{}{}
+
+	if criteria.CVSSRange != nil {
+		m["cvss_range"] = flattenCVSSRange(criteria.CVSSRange)
+	}
+	m["min_severity"] = criteria.MinimumSeverity
+
+	return []interface{}{m}
+}
+
+func flattenCVSSRange(cvss *PolicyCVSSRange) []interface{} {
+	if cvss == nil {
+		return []interface{}{}
+	}
+
+	m := map[string]interface{}{
+		"from": cvss.From,
+		"to":   cvss.To,
+	}
+	return []interface{}{m}
+}
+
+func flattenActions(actions *PolicyRuleActions) []interface{} {
+	if actions == nil {
+		return []interface{}{}
+	}
+
+	m := map[string]interface{}{
+		"block_download": flattenBlockDownload(actions.BlockDownload),
+	}
+	if actions.Webhooks != nil {
+		m["webhooks"] = *actions.Webhooks
+	}
+	if actions.Mails != nil {
+		m["mails"] = *actions.Mails
+	}
+	if actions.FailBuild != nil {
+		m["fail_build"] = *actions.FailBuild
+	}
+	if actions.BlockReleaseBundle != nil {
+		m["block_release_bundle_distribution"] = *actions.BlockReleaseBundle
+	}
+	if actions.NotifyWatchRecipients != nil {
+		m["notify_watch_recipients"] = *actions.NotifyWatchRecipients
+	}
+	if actions.NotifyDeployer != nil {
+		m["notify_deployer"] = *actions.NotifyDeployer
+	}
+	if actions.CreateJiraTicketEnabled != nil {
+		m["create_ticket_enabled"] = *actions.CreateJiraTicketEnabled
+	}
+	if actions.FailureGracePeriodDays != nil {
+		m["build_failure_grace_period_in_days"] = *actions.FailureGracePeriodDays // integer
+	}
+	if actions.CustomSeverity != nil {
+		m["custom_severity"] = *actions.CustomSeverity
+	}
+
+	return []interface{}{m}
+}
+
+func flattenBlockDownload(bd *BlockDownloadSettings) []interface{} {
+	if bd == nil {
+		return []interface{}{}
+	}
+
+	m := map[string]interface{}{}
+	if bd.Unscanned != nil {
+		m["unscanned"] = *bd.Unscanned
+	}
+	if bd.Active != nil {
+		m["active"] = *bd.Active
+	}
+
+	return []interface{}{m}
+}
+
+// Create Xray policy
+func resourceXrayPolicyCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+	policy, err := expandPolicy(d)
+	// Warning or errors can be collected in a slice type
+	var diags diag.Diagnostics
+	if err != nil {
+		return diag.FromErr(err)
+	}
+	_, err = m.(*resty.Client).R().SetBody(policy).Post("xray/api/v2/policies")
+	if err != nil {
+		return diag.FromErr(err)
+	}
+
+	d.SetId(*policy.Name)
+	resourceXrayPolicyRead(ctx, d, m)
+	return diags
+}
+
+// Get Xray policy by name
+func getPolicy(id string, client *resty.Client) (Policy, *resty.Response, error) {
+	policy := Policy{}
+	resp, err := client.R().SetResult(&policy).Get("xray/api/v2/policies/" + id)
+	return policy, resp, err
+}
+func resourceXrayPolicyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+	policy, resp, err := getPolicy(d.Id(), m.(*resty.Client))
+	var diags diag.Diagnostics
+	if err != nil {
+		if resp != nil && resp.StatusCode() == http.StatusNotFound {
+			log.Printf("[WARN] Xray policy (%s) not found, removing from state", d.Id())
+			d.SetId("")
+			return nil
+		}
+		return diag.FromErr(err)
+	}
+
+	if err := d.Set("name", policy.Name); err != nil {
+		return diag.FromErr(err)
+	}
+	if err := d.Set("type", policy.Type); err != nil {
+		return diag.FromErr(err)
+	}
+	if policy.Description != nil {
+		if err := d.Set("description", policy.Description); err != nil {
+			return diag.FromErr(err)
+		}
+	}
+	if err := d.Set("author", policy.Author); err != nil {
+		return diag.FromErr(err)
+	}
+	if err := d.Set("created", policy.Created); err != nil {
+		return diag.FromErr(err)
+	}
+	if err := d.Set("modified", policy.Modified); err != nil {
+		return diag.FromErr(err)
+	}
+	if *policy.Type == "license" {
+		if err := d.Set("rules", flattenLicenseRules(*policy.Rules)); err != nil {
+			return diag.FromErr(err)
+		}
+	}
+	if *policy.Type == "security" {
+		if err := d.Set("rules", flattenSecurityRules(*policy.Rules)); err != nil {
+			return diag.FromErr(err)
+		}
+	}
+	return diags
+}
+
+func resourceXrayPolicyUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+	policy, err := expandPolicy(d)
+	if err != nil {
+		return diag.FromErr(err)
+	}
+	_, err = m.(*resty.Client).R().SetBody(policy).Put("xray/api/v2/policies/" + d.Id())
+	if err != nil {
+		return diag.FromErr(err)
+	}
+
+	d.SetId(*policy.Name)
+	return resourceXrayPolicyRead(ctx, d, m)
+}
+
+func resourceXrayPolicyDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+	// Warning or errors can be collected in a slice type
+	var diags diag.Diagnostics
+	_, err := m.(*resty.Client).R().Delete("xray/api/v2/policies/" + d.Id())
+	if err != nil {
+		return diag.FromErr(err)
+	}
+	return diags
+}
diff --git a/pkg/xray/provider.go b/pkg/xray/provider.go
index 50abbae0..621b047d 100644
--- a/pkg/xray/provider.go
+++ b/pkg/xray/provider.go
@@ -18,24 +18,26 @@ func Provider() *schema.Provider {
 	p := &schema.Provider{
 		Schema: map[string]*schema.Schema{
 			"url": {
-				Type:         schema.TypeString,
-				Optional:     true,
-				DefaultFunc:  schema.EnvDefaultFunc("ARTIFACTORY_URL", "http://localhost:8082"),
+				Type:     schema.TypeString,
+				Optional: true,
+				DefaultFunc: schema.MultiEnvDefaultFunc([]string{"JFROG_URL", "ARTIFACTORY_URL", "PROJECTS_URL"},
+					"http://localhost:8081"),
 				ValidateFunc: validation.IsURLWithHTTPorHTTPS,
 			},
 			"access_token": {
-				Type:        schema.TypeString,
-				Optional:    true,
-				Sensitive:   true,
-				DefaultFunc: schema.EnvDefaultFunc("ARTIFACTORY_ACCESS_TOKEN", nil),
+				Type:      schema.TypeString,
+				Optional:  true,
+				Sensitive: true,
+				DefaultFunc: schema.MultiEnvDefaultFunc([]string{"XRAY_ACCESS_TOKEN", "ARTIFACTORY_ACCESS_TOKEN"},
+					"JFROG_ACCESS_TOKEN"),
 				Description: "This is a bearer token that can be given to you by your admin under `Identity and Access`",
 			},
 		},
 
 		ResourcesMap: map[string]*schema.Resource{
 			// Xray resources
-			"xray_policy": resourceXrayPolicy(),
-			"xray_watch":  resourceXrayWatch(),
+			"xray_security_policy": resourceXraySecurityPolicyV2(),
+			"xray_license_policy":  resourceXrayLicensePolicyV2(),
 		},
 	}
 
@@ -83,7 +85,7 @@ func addAuthToResty(client *resty.Client, accessToken string) (*resty.Client, er
 	return nil, fmt.Errorf("no authentication details supplied")
 }
 
-// Creates the client for artifactory, will prefer token auth over basic auth if both set
+// Creates the client for artifactory, will use token auth
 func providerConfigure(d *schema.ResourceData, terraformVersion string) (interface{}, error) {
 	URL, ok := d.GetOk("url")
 	if URL == nil || URL == "" || !ok {
diff --git a/pkg/xray/resource_xray_license_policy.go b/pkg/xray/resource_xray_license_policy.go
new file mode 100644
index 00000000..5c8e6475
--- /dev/null
+++ b/pkg/xray/resource_xray_license_policy.go
@@ -0,0 +1,168 @@
+package xray
+
+import (
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func resourceXrayLicensePolicyV2() *schema.Resource {
+	return &schema.Resource{
+		SchemaVersion: 1,
+		CreateContext: resourceXrayPolicyCreate,
+		ReadContext:   resourceXrayPolicyRead,
+		UpdateContext: resourceXrayPolicyUpdate,
+		DeleteContext: resourceXrayPolicyDelete,
+		Description: "Creates an xray policy using V2 of the underlying APIs. Please note: " +
+			"It's only compatible with Bearer token auth method (Identity and Access => Access Tokens",
+
+		Importer: &schema.ResourceImporter{
+			StateContext: schema.ImportStatePassthroughContext,
+		},
+
+		Schema: map[string]*schema.Schema{
+			"name": {
+				Type:     schema.TypeString,
+				Required: true,
+				ForceNew: true,
+			},
+			"description": {
+				Type:     schema.TypeString,
+				Optional: true,
+			},
+			"type": {
+				Type:     schema.TypeString,
+				Required: true,
+			},
+			"author": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"created": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"modified": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"rules": {
+				Type:     schema.TypeList,
+				Required: true,
+				Elem: &schema.Resource{
+					Schema: map[string]*schema.Schema{
+						"name": {
+							Type:     schema.TypeString,
+							Required: true,
+						},
+						"priority": {
+							Type:     schema.TypeInt,
+							Required: true,
+						},
+						"criteria": {
+							Type:     schema.TypeList,
+							Required: true,
+							MinItems: 1,
+							MaxItems: 1,
+							Elem: &schema.Resource{
+								Schema: map[string]*schema.Schema{
+									"banned_licenses": {
+										Type:     schema.TypeList,
+										Optional: true,
+										Elem: &schema.Schema{
+											Type: schema.TypeString,
+										},
+									},
+									"allowed_licenses": {
+										Type:     schema.TypeList,
+										Optional: true,
+										Elem: &schema.Schema{
+											Type: schema.TypeString,
+										},
+									},
+									"allow_unknown": {
+										Type:     schema.TypeBool,
+										Optional: true,
+									},
+									"multi_license_permissive": {
+										Type:     schema.TypeBool,
+										Optional: true,
+									},
+								},
+							},
+						},
+						"actions": {
+							Type:     schema.TypeList,
+							Optional: true,
+							MaxItems: 1,
+							Elem: &schema.Resource{
+								Schema: map[string]*schema.Schema{
+									"webhooks": {
+										Type:     schema.TypeList,
+										Optional: true,
+										Elem: &schema.Schema{
+											Type: schema.TypeString,
+										},
+									},
+									"mails": {
+										Type:     schema.TypeList,
+										Optional: true,
+										Elem: &schema.Schema{
+											Type: schema.TypeString,
+										},
+									},
+									"block_download": {
+										Type:     schema.TypeList,
+										Required: true,
+										MaxItems: 1,
+										Elem: &schema.Resource{
+											Schema: map[string]*schema.Schema{
+												"unscanned": {
+													Type:     schema.TypeBool,
+													Required: true,
+												},
+												"active": {
+													Type:     schema.TypeBool,
+													Required: true,
+												},
+											},
+										},
+									},
+									"block_release_bundle_distribution": {
+										Type:     schema.TypeBool,
+										Optional: true,
+									},
+									"fail_build": {
+										Type:     schema.TypeBool,
+										Optional: true,
+									},
+									"notify_deployer": {
+										Type:     schema.TypeBool,
+										Optional: true,
+									},
+									"notify_watch_recipients": {
+										Type:     schema.TypeBool,
+										Optional: true,
+									},
+									"create_ticket_enabled": {
+										Type:     schema.TypeBool,
+										Optional: true,
+										Default:  false,
+									},
+									"custom_severity": {
+										Type:     schema.TypeString,
+										Optional: true,
+										Default:  "High",
+									},
+									"build_failure_grace_period_in_days": {
+										Type:     schema.TypeInt,
+										Optional: true,
+										Default:  3,
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+}
diff --git a/pkg/xray/resource_xray_policy.go b/pkg/xray/resource_xray_policy.go
deleted file mode 100644
index e081c234..00000000
--- a/pkg/xray/resource_xray_policy.go
+++ /dev/null
@@ -1,559 +0,0 @@
-package xray
-
-import (
-	"fmt"
-	"github.com/go-resty/resty/v2"
-	"log"
-	"net/http"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-)
-
-// PolicyCVSSRange All of this was ripped out of it's original location and copied here.
-// The original provider code used th v1 API, which is not supported in the JFROG go client
-// The current objective is to rip out any dependencies not from jfrog. So, jfrog doesn't support it
-// I need backward compatibility, and I can't have any other dependencies.
-type PolicyCVSSRange struct {
-	To   *int `json:"to,omitempty"`
-	From *int `json:"from,omitempty"`
-}
-
-type PolicyRuleCriteria struct {
-	// Security Criteria
-	MinimumSeverity *string          `json:"min_severity,omitempty"`
-	CVSSRange       *PolicyCVSSRange `json:"cvss_range,omitempty"`
-
-	// License Criteria
-	AllowUnknown    *bool     `json:"allow_unknown,omitempty"`
-	BannedLicenses  *[]string `json:"banned_licenses,omitempty"`
-	AllowedLicenses *[]string `json:"allowed_licenses,omitempty"`
-}
-
-type BlockDownloadSettings struct {
-	Unscanned *bool `json:"unscanned,omitempty"`
-	Active    *bool `json:"active,omitempty"`
-}
-
-type PolicyRuleActions struct {
-	Mails          *[]string              `json:"mails,omitempty"`
-	FailBuild      *bool                  `json:"fail_build,omitempty"`
-	BlockDownload  *BlockDownloadSettings `json:"block_download,omitempty"`
-	Webhooks       *[]string              `json:"webhooks,omitempty"`
-	CustomSeverity *string                `json:"custom_severity,omitempty"`
-}
-
-type PolicyRule struct {
-	Name     *string             `json:"name,omitempty"`
-	Priority *int                `json:"priority,omitempty"`
-	Criteria *PolicyRuleCriteria `json:"criteria,omitempty"`
-	Actions  *PolicyRuleActions  `json:"actions,omitempty"`
-}
-
-type Policy struct {
-	Name        *string       `json:"name,omitempty"`
-	Type        *string       `json:"type,omitempty"`
-	Author      *string       `json:"author,omitempty"`
-	Description *string       `json:"description,omitempty"`
-	Rules       *[]PolicyRule `json:"rules,omitempty"`
-	Created     *string       `json:"created,omitempty"`
-	Modified    *string       `json:"modified,omitempty"`
-}
-
-func resourceXrayPolicy() *schema.Resource {
-	return &schema.Resource{
-		SchemaVersion:      1,
-		Create:             resourceXrayPolicyCreate,
-		Read:               resourceXrayPolicyRead,
-		Update:             resourceXrayPolicyUpdate,
-		Delete:             resourceXrayPolicyDelete,
-		DeprecationMessage: "This portion of the provider uses V1 apis and will eventually be removed",
-		Description: "Creates an xray policy using V1 of the underlying APIs. Please note: " +
-			"It's only compatible with Bearer token auth method (Identity and Access => Access Tokens",
-
-		Importer: &schema.ResourceImporter{
-			State: schema.ImportStatePassthrough,
-		},
-
-		Schema: map[string]*schema.Schema{
-			"name": {
-				Type:     schema.TypeString,
-				Required: true,
-				ForceNew: true,
-			},
-			"type": {
-				Type:     schema.TypeString,
-				Required: true,
-			},
-			"description": {
-				Type:     schema.TypeString,
-				Optional: true,
-			},
-			"author": {
-				Type:     schema.TypeString,
-				Computed: true,
-			},
-			"created": {
-				Type:     schema.TypeString,
-				Computed: true,
-			},
-			"modified": {
-				Type:     schema.TypeString,
-				Computed: true,
-			},
-
-			"rules": {
-				Type:     schema.TypeList,
-				Required: true,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"name": {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						"priority": {
-							Type:     schema.TypeInt,
-							Required: true,
-						},
-
-						"criteria": {
-							Type:     schema.TypeList,
-							Required: true,
-							MinItems: 1,
-							MaxItems: 1,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									// Security criteria
-									"min_severity": {
-										Type:     schema.TypeString,
-										Optional: true,
-									},
-									"cvss_range": {
-										Type:     schema.TypeList,
-										Optional: true,
-										MaxItems: 1,
-										Elem: &schema.Resource{
-											Schema: map[string]*schema.Schema{
-												"from": {
-													Type:     schema.TypeInt, // Yes, the xray web ui allows floats. The go library says ints. :(
-													Required: true,
-												},
-												"to": {
-													Type:     schema.TypeInt,
-													Required: true,
-												},
-											},
-										},
-									},
-									// License Criteria
-									"allow_unknown": {
-										Type:     schema.TypeBool,
-										Optional: true,
-									},
-									"banned_licenses": {
-										Type:     schema.TypeList,
-										Optional: true,
-										Elem: &schema.Schema{
-											Type: schema.TypeString,
-										},
-									},
-									"allowed_licenses": {
-										Type:     schema.TypeList,
-										Optional: true,
-										Elem: &schema.Schema{
-											Type: schema.TypeString,
-										},
-									},
-								},
-							},
-						},
-						"actions": {
-							Type:     schema.TypeList,
-							Optional: true,
-							MaxItems: 1,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"mails": {
-										Type:     schema.TypeList,
-										Optional: true,
-										Elem: &schema.Schema{
-											Type: schema.TypeString,
-										},
-									},
-									"fail_build": {
-										Type:     schema.TypeBool,
-										Optional: true,
-									},
-									"block_download": {
-										Type:     schema.TypeList,
-										Required: true,
-										// TODO: In an ideal world, this would be optional (see note in expandActions)
-										MaxItems: 1,
-										Elem: &schema.Resource{
-											Schema: map[string]*schema.Schema{
-												"unscanned": {
-													Type:     schema.TypeBool,
-													Required: true,
-												},
-												"active": {
-													Type:     schema.TypeBool,
-													Required: true,
-												},
-											},
-										},
-									},
-									"webhooks": {
-										Type:     schema.TypeList,
-										Optional: true,
-										Elem: &schema.Schema{
-											Type: schema.TypeString,
-										},
-									},
-									"custom_severity": {
-										Type:     schema.TypeString,
-										Optional: true,
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-		},
-	}
-}
-
-func expandPolicy(d *schema.ResourceData) (*Policy, error) {
-	policy := new(Policy)
-
-	policy.Name = StringPtr(d.Get("name").(string))
-	if v, ok := d.GetOk("type"); ok {
-		policy.Type = StringPtr(v.(string))
-	}
-	if v, ok := d.GetOk("description"); ok {
-		policy.Description = StringPtr(v.(string))
-	}
-	if v, ok := d.GetOk("author"); ok {
-		policy.Author = StringPtr(v.(string))
-	}
-	policyRules, err := expandRules(d.Get("rules").([]interface{}), policy.Type)
-	policy.Rules = &policyRules
-
-	return policy, err
-}
-
-func expandRules(configured []interface{}, policyType *string) (policyRules []PolicyRule, err error) {
-	rules := make([]PolicyRule, 0, len(configured))
-
-	for _, raw := range configured {
-		rule := new(PolicyRule)
-		data := raw.(map[string]interface{})
-		rule.Name = StringPtr(data["name"].(string))
-		rule.Priority = IntPtr(data["priority"].(int))
-
-		rule.Criteria, err = expandCriteria(data["criteria"].([]interface{}), policyType)
-		if v, ok := data["actions"]; ok {
-			rule.Actions = expandActions(v.([]interface{}))
-		}
-		rules = append(rules, *rule)
-	}
-
-	return rules, err
-}
-
-func expandCriteria(l []interface{}, policyType *string) (*PolicyRuleCriteria, error) {
-	if len(l) == 0 {
-		return nil, nil
-	}
-
-	m := l[0].(map[string]interface{}) // We made this a list of one to make schema validation easier
-	criteria := new(PolicyRuleCriteria)
-
-	// The API doesn't allow both severity and license criteria to be _set_, even if they have empty values
-	// So we have to figure out which group is actually empty and not even set it
-	minSev := StringPtr(m["min_severity"].(string))
-	cvss := expandCVSSRange(m["cvss_range"].([]interface{}))
-	allowUnk := BoolPtr(m["allow_unknown"].(bool))
-	banned := expandLicenses(m["banned_licenses"].([]interface{}))
-	allowed := expandLicenses(m["allowed_licenses"].([]interface{}))
-
-	licenseType := "license"
-	securityType := "security"
-
-	if *minSev == "" && cvss == nil {
-		if *policyType == securityType {
-			return nil, fmt.Errorf("allow_unknown, banned_licenses, and allowed_licenses are not supported with security policies")
-		}
-
-		// If these are both the default values, we must be using license criteria
-		criteria.AllowUnknown = allowUnk
-		criteria.BannedLicenses = banned
-		criteria.AllowedLicenses = allowed
-	} else {
-		if *policyType == licenseType {
-			return nil, fmt.Errorf("min_severity and cvvs_range are not supported with license policies")
-		}
-
-		// This is also picky about not allowing empty values to be set
-		if cvss == nil {
-			criteria.MinimumSeverity = minSev
-		} else {
-			criteria.CVSSRange = cvss
-		}
-	}
-
-	return criteria, nil
-}
-
-func expandCVSSRange(l []interface{}) *PolicyCVSSRange {
-	if len(l) == 0 {
-		return nil
-	}
-
-	m := l[0].(map[string]interface{})
-	cvssrange := &PolicyCVSSRange{
-		From: IntPtr(m["from"].(int)),
-		To:   IntPtr(m["to"].(int)),
-	}
-	return cvssrange
-}
-
-func expandLicenses(l []interface{}) *[]string {
-	if len(l) == 0 {
-		return nil
-	}
-
-	licenses := make([]string, 0, len(l))
-	for _, license := range l {
-		licenses = append(licenses, license.(string))
-	}
-	return &licenses
-}
-
-func expandActions(l []interface{}) *PolicyRuleActions {
-	if len(l) == 0 {
-		return nil
-	}
-
-	actions := new(PolicyRuleActions)
-	m := l[0].(map[string]interface{}) // We made this a list of one to make schema validation easier
-
-	if v, ok := m["mails"]; ok && len(v.([]interface{})) > 0 {
-		m := v.([]interface{})
-		mails := make([]string, 0, len(m))
-		for _, mail := range m {
-			mails = append(mails, mail.(string))
-		}
-		actions.Mails = &mails
-	}
-	if v, ok := m["fail_build"]; ok {
-		actions.FailBuild = BoolPtr(v.(bool))
-	}
-
-	if v, ok := m["block_download"]; ok {
-		if len(v.([]interface{})) > 0 {
-			vList := v.([]interface{})
-			vMap := vList[0].(map[string]interface{})
-
-			actions.BlockDownload = &BlockDownloadSettings{
-				Unscanned: BoolPtr(vMap["unscanned"].(bool)),
-				Active:    BoolPtr(vMap["active"].(bool)),
-			}
-		} else {
-			actions.BlockDownload = &BlockDownloadSettings{
-				Unscanned: BoolPtr(false),
-				Active:    BoolPtr(false),
-			}
-			// Setting this false/false block feels like it _should_ work, since putting a false/false block in the terraform resource works fine
-			// However, it doesn't, and we end up getting this diff when running acceptance tests when this is optional in the schema
-			// rules.0.actions.0.block_download.#:           "1" => "0"
-			// rules.0.actions.0.block_download.0.active:    "false" => ""
-			// rules.0.actions.0.block_download.0.unscanned: "false" => ""
-		}
-	}
-
-	if v, ok := m["webhooks"]; ok && len(v.([]interface{})) > 0 {
-		m := v.([]interface{})
-		webhooks := make([]string, 0, len(m))
-		for _, hook := range m {
-			webhooks = append(webhooks, hook.(string))
-		}
-		actions.Webhooks = &webhooks
-	}
-	if v, ok := m["custom_severity"]; ok {
-		gosucks := v.(string)
-		actions.CustomSeverity = &gosucks
-	}
-
-	return actions
-}
-
-func flattenRules(rules []PolicyRule) []interface{} {
-	l := make([]interface{}, len(rules))
-
-	for i, rule := range rules {
-		m := map[string]interface{}{
-			"name":     *rule.Name,
-			"priority": *rule.Priority,
-			"criteria": flattenCriteria(rule.Criteria),
-			"actions":  flattenActions(rule.Actions),
-		}
-		l[i] = m
-	}
-
-	return l
-}
-
-func flattenCriteria(criteria *PolicyRuleCriteria) []interface{} {
-	if criteria == nil {
-		return []interface{}{}
-	}
-
-	m := map[string]interface{}{
-		"cvss_range": flattenCVSSRange(criteria.CVSSRange),
-	}
-
-	if criteria.MinimumSeverity != nil {
-		m["min_severity"] = *criteria.MinimumSeverity
-	}
-	if criteria.AllowUnknown != nil {
-		m["allow_unknown"] = *criteria.AllowUnknown // Same typo in the library
-	}
-	if criteria.BannedLicenses != nil {
-		m["banned_licenses"] = *criteria.BannedLicenses
-	}
-	if criteria.AllowedLicenses != nil {
-		m["allowed_licenses"] = *criteria.AllowedLicenses
-	}
-
-	return []interface{}{m}
-}
-
-func flattenCVSSRange(cvss *PolicyCVSSRange) []interface{} {
-	if cvss == nil {
-		return []interface{}{}
-	}
-
-	m := map[string]interface{}{
-		"from": *cvss.From,
-		"to":   *cvss.To,
-	}
-	return []interface{}{m}
-}
-
-func flattenActions(actions *PolicyRuleActions) []interface{} {
-	if actions == nil {
-		return []interface{}{}
-	}
-
-	m := map[string]interface{}{
-		"block_download": flattenBlockDownload(actions.BlockDownload),
-	}
-
-	if actions.Mails != nil {
-		m["mails"] = *actions.Mails
-	}
-	if actions.FailBuild != nil {
-		m["fail_build"] = *actions.FailBuild
-	}
-	if actions.Webhooks != nil {
-		m["webhooks"] = *actions.Webhooks
-	}
-	if actions.CustomSeverity != nil {
-		m["custom_severity"] = *actions.CustomSeverity
-	}
-
-	return []interface{}{m}
-}
-
-func flattenBlockDownload(bd *BlockDownloadSettings) []interface{} {
-	if bd == nil {
-		return []interface{}{}
-	}
-
-	m := map[string]interface{}{}
-	if bd.Unscanned != nil {
-		m["unscanned"] = *bd.Unscanned
-	}
-	if bd.Active != nil {
-		m["active"] = *bd.Active
-	}
-
-	return []interface{}{m}
-}
-
-func resourceXrayPolicyCreate(d *schema.ResourceData, m interface{}) error {
-
-	policy, err := expandPolicy(d)
-	if err != nil {
-		return err
-	}
-	_, err = m.(*resty.Client).R().SetBody(policy).Post("xray/api/v1/policies")
-	if err != nil {
-		return err
-	}
-
-	d.SetId(*policy.Name)
-	return resourceXrayPolicyRead(d, m)
-}
-
-func getPolicy(id string, client *resty.Client) (Policy, *resty.Response, error) {
-	policy := Policy{}
-	resp, err := client.R().SetResult(&policy).Put("xray/api/v1/policies/" + id)
-	return policy, resp, err
-}
-func resourceXrayPolicyRead(d *schema.ResourceData, m interface{}) error {
-	policy, resp, err := getPolicy(d.Id(), m.(*resty.Client))
-	if err != nil {
-		if resp != nil && resp.StatusCode() == http.StatusNotFound {
-			log.Printf("[WARN] Xray policy (%s) not found, removing from state", d.Id())
-			d.SetId("")
-			return nil
-		}
-		return err
-	}
-
-	if err := d.Set("name", *policy.Name); err != nil {
-		return err
-	}
-	if err := d.Set("type", *policy.Type); err != nil {
-		return err
-	}
-	if policy.Description != nil {
-		if err := d.Set("description", *policy.Description); err != nil {
-			return err
-		}
-	}
-	if err := d.Set("author", *policy.Author); err != nil {
-		return err
-	}
-	if err := d.Set("created", *policy.Created); err != nil {
-		return err
-	}
-	if err := d.Set("modified", *policy.Modified); err != nil {
-		return err
-	}
-	if err := d.Set("rules", flattenRules(*policy.Rules)); err != nil {
-		return err
-	}
-	return nil
-}
-
-func resourceXrayPolicyUpdate(d *schema.ResourceData, m interface{}) error {
-
-	policy, err := expandPolicy(d)
-	if err != nil {
-		return err
-	}
-	_, err = m.(*resty.Client).R().SetBody(policy).Put("xray/api/v1/policies/" + d.Id())
-	if err != nil {
-		return err
-	}
-
-	d.SetId(*policy.Name)
-	return resourceXrayPolicyRead(d, m)
-}
-
-func resourceXrayPolicyDelete(d *schema.ResourceData, m interface{}) error {
-	_, err := m.(*resty.Client).R().Delete("xray/api/v1/policies/" + d.Id())
-	return err
-}
diff --git a/pkg/xray/resource_xray_security_policy.go b/pkg/xray/resource_xray_security_policy.go
new file mode 100644
index 00000000..aa1dae64
--- /dev/null
+++ b/pkg/xray/resource_xray_security_policy.go
@@ -0,0 +1,168 @@
+package xray
+
+import (
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+func resourceXraySecurityPolicyV2() *schema.Resource {
+	return &schema.Resource{
+		SchemaVersion: 1,
+		CreateContext: resourceXrayPolicyCreate,
+		ReadContext:   resourceXrayPolicyRead,
+		UpdateContext: resourceXrayPolicyUpdate,
+		DeleteContext: resourceXrayPolicyDelete,
+		Description: "Creates an xray policy using V2 of the underlying APIs. Please note: " +
+			"It's only compatible with Bearer token auth method (Identity and Access => Access Tokens",
+
+		Importer: &schema.ResourceImporter{
+			StateContext: schema.ImportStatePassthroughContext,
+		},
+
+		Schema: map[string]*schema.Schema{
+			"name": {
+				Type:     schema.TypeString,
+				Required: true,
+				ForceNew: true,
+			},
+			"description": {
+				Type:     schema.TypeString,
+				Optional: true,
+			},
+			"type": {
+				Type:     schema.TypeString,
+				Required: true,
+			},
+			// not in create policy body, but it is in the get call response.
+			"author": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"created": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			"modified": {
+				Type:     schema.TypeString,
+				Computed: true,
+			},
+			//
+			"rules": {
+				Type:     schema.TypeList,
+				Required: true,
+				Elem: &schema.Resource{
+					Schema: map[string]*schema.Schema{
+						"name": {
+							Type:     schema.TypeString,
+							Required: true,
+						},
+						"priority": {
+							Type:     schema.TypeInt,
+							Required: true,
+						},
+						"criteria": {
+							Type:     schema.TypeList,
+							Required: true,
+							MinItems: 1,
+							MaxItems: 1,
+							Elem: &schema.Resource{
+								Schema: map[string]*schema.Schema{
+									"min_severity": {
+										Type:     schema.TypeString,
+										Optional: true,
+									},
+									"cvss_range": {
+										Type:     schema.TypeList,
+										Optional: true,
+										MaxItems: 1,
+										Elem: &schema.Resource{
+											Schema: map[string]*schema.Schema{
+												"from": {
+													Type:     schema.TypeFloat,
+													Required: true,
+												},
+												"to": {
+													Type:     schema.TypeFloat,
+													Required: true,
+												},
+											},
+										},
+									},
+								},
+							},
+						},
+						"actions": {
+							Type:     schema.TypeList,
+							Optional: true,
+							MaxItems: 1,
+							Elem: &schema.Resource{
+								Schema: map[string]*schema.Schema{
+									"webhooks": {
+										Type:     schema.TypeList,
+										Optional: true,
+										Elem: &schema.Schema{
+											Type: schema.TypeString,
+										},
+									},
+									"mails": {
+										Type:     schema.TypeList,
+										Optional: true,
+										Elem: &schema.Schema{
+											Type: schema.TypeString,
+										},
+									},
+									"block_download": {
+										Type:     schema.TypeList,
+										Required: true,
+										MaxItems: 1,
+										Elem: &schema.Resource{
+											Schema: map[string]*schema.Schema{
+												"unscanned": {
+													Type:     schema.TypeBool,
+													Required: true,
+												},
+												"active": {
+													Type:     schema.TypeBool,
+													Required: true,
+												},
+											},
+										},
+									},
+									"block_release_bundle_distribution": {
+										Type:     schema.TypeBool,
+										Optional: true,
+										Default:  true,
+									},
+									"fail_build": {
+										Type:     schema.TypeBool,
+										Optional: true,
+										Default:  true,
+									},
+									"notify_deployer": {
+										Type:     schema.TypeBool,
+										Optional: true,
+										Default:  false,
+									},
+									"notify_watch_recipients": {
+										Type:     schema.TypeBool,
+										Optional: true,
+										Default:  false,
+									},
+									"create_ticket_enabled": {
+										Type:     schema.TypeBool,
+										Optional: true,
+										Default:  false,
+									},
+									"build_failure_grace_period_in_days": {
+										Type:     schema.TypeInt,
+										Optional: true,
+										Default:  3,
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+}
diff --git a/pkg/xray/resource_xray_watch.go b/pkg/xray/resource_xray_watch.go
deleted file mode 100644
index 13a83568..00000000
--- a/pkg/xray/resource_xray_watch.go
+++ /dev/null
@@ -1,363 +0,0 @@
-package xray
-
-import (
-	"log"
-	"net/http"
-
-	"github.com/go-resty/resty/v2"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
-)
-
-// WatchGeneralData this struct and all the others below it line up identically with the
-// structs from the V2 go client from jfrog with one fatal exception: None of these nested types is exported
-// and it's totally inconsistent with the rest of the code.
-// Option are: move this code into the terraform space, as is, or beg the jfrog-go-client
-// team to captial case those variables. I ticket will be filed, but I am not hopeful.
-type WatchGeneralData struct {
-	Name        *string `json:"name,omitempty"`
-	Description *string `json:"description,omitempty"`
-	Active      *bool   `json:"active,omitempty"`
-}
-
-type WatchFilterValue struct {
-	Key   *string `json:"key,omitempty"`
-	Value *string `json:"value,omitempty"`
-}
-
-// WatchFilterValueWrapper is a wrapper around WatchFilterValue which handles the API returning both a string and an object for the watch filter value
-type WatchFilterValueWrapper struct {
-	WatchFilterValue
-	IsPropertyFilter bool `json:”-”`
-}
-
-type WatchFilter struct {
-	Type  *string                  `json:"type,omitempty"`
-	Value *WatchFilterValueWrapper `json:"value,omitempty"`
-}
-
-type WatchProjectResource struct {
-	Type            *string        `json:"type,omitempty"`
-	RepoType        *string        `json:"repo_type,omitempty"`
-	BinaryManagerId *string        `json:"bin_mgr_id,omitempty"`
-	Name            *string        `json:"name,omitempty"`
-	Filters         *[]WatchFilter `json:"filters,omitempty"`
-}
-
-type WatchProjectResources struct {
-	Resources *[]WatchProjectResource `json:"resources,omitempty"`
-}
-
-type WatchAssignedPolicy struct {
-	Name *string `json:"name,omitempty"`
-	Type *string `json:"type,omitempty"`
-}
-
-type Watch struct {
-	GeneralData      *WatchGeneralData      `json:"general_data,omitempty"`
-	ProjectResources *WatchProjectResources `json:"project_resources,omitempty"`
-	AssignedPolicies *[]WatchAssignedPolicy `json:"assigned_policies,omitempty"`
-}
-
-func resourceXrayWatch() *schema.Resource {
-	return &schema.Resource{
-		Create: resourceXrayWatchCreate,
-		Read:   resourceXrayWatchRead,
-		Update: resourceXrayWatchUpdate,
-		Delete: resourceXrayWatchDelete,
-
-		Importer: &schema.ResourceImporter{
-			State: schema.ImportStatePassthrough,
-		},
-
-		Schema: map[string]*schema.Schema{
-			"name": {
-				Type:     schema.TypeString,
-				Required: true,
-				ForceNew: true,
-			},
-			"description": {
-				Type:     schema.TypeString,
-				Optional: true,
-			},
-			"active": {
-				Type:     schema.TypeBool,
-				Optional: true,
-			},
-
-			"resources": {
-				Type:     schema.TypeList,
-				Required: true,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"type": {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						"name": {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						"bin_mgr_id": {
-							Type:     schema.TypeString,
-							Optional: true,
-						},
-						"repo_type": {
-							Type:     schema.TypeString,
-							Optional: true,
-							Computed: true,
-							ValidateFunc: validation.StringInSlice([]string{
-								"local",
-								"remote",
-							}, false),
-						},
-						"filters": {
-							Type:     schema.TypeList,
-							Optional: true,
-							Elem: &schema.Resource{
-								Schema: map[string]*schema.Schema{
-									"type": {
-										Type:     schema.TypeString,
-										Required: true,
-									},
-									// TODO this can be either a string or possibly a json blob
-									// eg "value":{"ExcludePatterns":[],"IncludePatterns":["*"]}
-									"value": {
-										Type:     schema.TypeString,
-										Required: true,
-									},
-								},
-							},
-						},
-					},
-				},
-			},
-
-			"assigned_policies": {
-				Type:     schema.TypeList,
-				Required: true,
-				Elem: &schema.Resource{
-					Schema: map[string]*schema.Schema{
-						"name": {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-						"type": {
-							Type:     schema.TypeString,
-							Required: true,
-						},
-					},
-				},
-			},
-
-			"watch_recipients": {
-				Type:     schema.TypeList,
-				Optional: true,
-				Elem: &schema.Schema{
-					Type: schema.TypeString,
-				},
-			},
-		},
-	}
-}
-
-func expandWatch(d *schema.ResourceData) *Watch {
-	watch := new(Watch)
-
-	gd := &WatchGeneralData{
-		Name: StringPtr(d.Get("name").(string)),
-	}
-	if v, ok := d.GetOk("description"); ok {
-		gd.Description = StringPtr(v.(string))
-	}
-	if v, ok := d.GetOk("active"); ok {
-		gd.Active = BoolPtr(v.(bool))
-	}
-	watch.GeneralData = gd
-
-	pr := &WatchProjectResources{}
-	if v, ok := d.GetOk("resources"); ok {
-		r := &[]WatchProjectResource{}
-		for _, res := range v.([]interface{}) {
-			*r = append(*r, *expandProjectResource(res))
-		}
-		pr.Resources = r
-	}
-	watch.ProjectResources = pr
-
-	ap := &[]WatchAssignedPolicy{}
-	if v, ok := d.GetOk("assigned_policies"); ok {
-		for _, pol := range v.([]interface{}) {
-			*ap = append(*ap, *expandAssignedPolicy(pol))
-		}
-	}
-	watch.AssignedPolicies = ap
-
-	return watch
-}
-
-func expandProjectResource(rawCfg interface{}) *WatchProjectResource {
-	resource := new(WatchProjectResource)
-
-	cfg := rawCfg.(map[string]interface{})
-	resource.Type = StringPtr(cfg["type"].(string))
-	if v, ok := cfg["bin_mgr_id"]; ok {
-		resource.BinaryManagerId = StringPtr(v.(string))
-	}
-	if v, ok := cfg["repo_type"]; ok {
-		resource.RepoType = StringPtr(v.(string))
-	}
-	if v, ok := cfg["name"]; ok {
-		resource.Name = StringPtr(v.(string))
-	}
-	if v, ok := cfg["filters"]; ok {
-		resourceFilters := expandFilters(v.([]interface{}))
-		resource.Filters = &resourceFilters
-	}
-
-	return resource
-}
-
-func expandFilters(l []interface{}) []WatchFilter {
-	filters := make([]WatchFilter, 0, len(l))
-
-	for _, raw := range l {
-		filter := new(WatchFilter)
-		f := raw.(map[string]interface{})
-		filter.Type = StringPtr(f["type"].(string))
-		valueWrapper := new(WatchFilterValueWrapper)
-		fv := new(WatchFilterValue)
-		fv.Value = StringPtr(f["value"].(string))
-		valueWrapper.WatchFilterValue = *fv
-		filter.Value = valueWrapper
-
-		filters = append(filters, *filter)
-	}
-
-	return filters
-}
-
-func expandAssignedPolicy(rawCfg interface{}) *WatchAssignedPolicy {
-	policy := new(WatchAssignedPolicy)
-
-	cfg := rawCfg.(map[string]interface{})
-	policy.Name = StringPtr(cfg["name"].(string))
-	policy.Type = StringPtr(cfg["type"].(string))
-
-	return policy
-}
-
-func flattenProjectResources(resources *WatchProjectResources) []interface{} {
-	if resources == nil || resources.Resources == nil {
-		return []interface{}{}
-	}
-
-	var l []interface{}
-	for _, res := range *resources.Resources {
-		m := make(map[string]interface{})
-		m["type"] = res.Type
-		if res.Name != nil {
-			m["name"] = res.Name
-		}
-		if res.BinaryManagerId != nil {
-			m["bin_mgr_id"] = res.BinaryManagerId
-		}
-		if res.RepoType != nil {
-			m["repo_type"] = res.RepoType
-		}
-		m["filters"] = flattenFilters(res.Filters)
-		l = append(l, m)
-	}
-
-	return l
-}
-
-func flattenFilters(filters *[]WatchFilter) []interface{} {
-	if filters == nil {
-		return []interface{}{}
-	}
-
-	var l []interface{}
-	for _, f := range *filters {
-		m := make(map[string]interface{})
-		m["type"] = f.Type
-		m["value"] = f.Value.WatchFilterValue.Value
-		l = append(l, m)
-	}
-
-	return l
-}
-
-func flattenAssignedPolicies(policies *[]WatchAssignedPolicy) []interface{} {
-	if policies == nil {
-		return []interface{}{}
-	}
-
-	var l []interface{}
-	for _, p := range *policies {
-		m := make(map[string]interface{})
-		m["name"] = p.Name
-		m["type"] = p.Type
-		l = append(l, m)
-	}
-
-	return l
-}
-
-func resourceXrayWatchCreate(d *schema.ResourceData, m interface{}) error {
-
-	watch := expandWatch(d)
-	_, err := m.(*resty.Client).R().SetBody(&watch).Post("xray/api/v2/watches")
-	if err != nil {
-		return err
-	}
-
-	d.SetId(*watch.GeneralData.Name) // ID may be returned according to the API docs, but not in go-xray
-	return resourceXrayWatchRead(d, m)
-}
-
-func resourceXrayWatchRead(d *schema.ResourceData, m interface{}) error {
-	watch := Watch{}
-	resp, err := m.(*resty.Client).R().SetResult(&watch).Get("xray/api/v2/watches/" + d.Id())
-	if err != nil {
-
-		if resp != nil && resp.StatusCode() == http.StatusNotFound {
-			log.Printf("[WARN] Xray watch (%s) not found, removing from state", d.Id())
-			d.SetId("")
-			return nil
-		}
-		return err
-	}
-
-	if err := d.Set("description", watch.GeneralData.Description); err != nil {
-		return err
-	}
-	if err := d.Set("active", watch.GeneralData.Active); err != nil {
-		return err
-	}
-	if err := d.Set("resources", flattenProjectResources(watch.ProjectResources)); err != nil {
-		return err
-	}
-	if err := d.Set("assigned_policies", flattenAssignedPolicies(watch.AssignedPolicies)); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func resourceXrayWatchUpdate(d *schema.ResourceData, m interface{}) error {
-	watch := expandWatch(d)
-	_, err := m.(*resty.Client).R().SetBody(&watch).Put("xray/api/v2/watches/" + d.Id())
-	if err != nil {
-		return err
-	}
-
-	d.SetId(*watch.GeneralData.Name)
-	return resourceXrayWatchRead(d, m)
-}
-
-func resourceXrayWatchDelete(d *schema.ResourceData, m interface{}) error {
-	_, err := m.(*resty.Client).R().Delete("xray/api/v2/watches/" + d.Id())
-	return err
-}
diff --git a/pkg/xray/util.go b/pkg/xray/util.go
index c615223c..b9d8fef7 100644
--- a/pkg/xray/util.go
+++ b/pkg/xray/util.go
@@ -119,6 +119,13 @@ var randomInt = func() func() int {
 	return rand.Int
 }()
 
+func copyStringMap(source map[string]string, target map[string]string) map[string]string {
+	for k, v := range source {
+		target[k] = v
+	}
+	return target
+}
+
 func mergeMaps(schemata ...map[string]interface{}) map[string]interface{} {
 	result := map[string]interface{}{}
 	for _, schma := range schemata {
@@ -180,4 +187,6 @@ func IntPtr(v int) *int { return &v }
 
 func Int64Ptr(v int64) *int64 { return &v }
 
+func Float64Ptr(v float64) *float64 { return &v }
+
 func StringPtr(v string) *string { return &v }
diff --git a/sample.tf b/sample.tf
index 8711d086..cee2790d 100644
--- a/sample.tf
+++ b/sample.tf
@@ -9,56 +9,128 @@ terraform {
 }
 
 provider "xray" {
-  //  supply ARTIFACTORY_USERNAME, _PASSWORD and _URL as env vars
+  //  supply ARTIFACTORY_URL (or JFROG_URL) and ARTIFACTORY_ACCESS_TOKEN (or XRAY_ACCESS_TOKEN/JFROG_ACCESS_TOKEN) as env vars
 }
-resource "xray_policy" "test" {
-  name        = "test-policy-name-severity"
-  description = "test policy description"
+
+resource "random_id" "randid" {
+  byte_length = 2
+}
+
+resource "xray_security_policy" "security1" {
+  name        = "test-security-policy-severity-${random_id.randid.dec}"
+  description = "Security policy description"
   type        = "security"
   rules {
-    name     = "rule-name"
+    name     = "rule-name-severity"
     priority = 1
     criteria {
       min_severity = "High"
     }
     actions {
+      webhooks = []
+      mails    = ["test@email.com"]
       block_download {
         unscanned = true
         active    = true
       }
+      block_release_bundle_distribution  = true
+      fail_build                         = true
+      notify_watch_recipients            = true
+      notify_deployer                    = true
+      create_ticket_enabled              = false  // set to true only if Jira integration is enabled
+      build_failure_grace_period_in_days = 5      // use only if fail_build is enabled
     }
   }
 }
 
-resource "xray_watch" "test" {
-  name        = "watch-npm-local-repo"
-  description = "apply a severity-based policy to the npm local repo"
-
-  resources {
-    type       = "repository"
-    name       = "npm-local"
-    bin_mgr_id = "example-com-artifactory-instance"
-    repo_type  = "local"
-    filters {
-      type  = "package-type"
-      value = "Npm"
+resource "xray_security_policy" "security2" {
+  name        = "test-security-policy-cvss-${random_id.randid.dec}"
+  description = "Security policy description"
+  type        = "security"
+  rules {
+    name     = "rule-name-cvss"
+    priority = 1
+    criteria {
+      cvss_range {
+        from = 1.5
+        to   = 5.3
+      }
+    }
+    actions {
+      webhooks = []
+      mails    = ["test@email.com"]
+      block_download {
+        unscanned = true
+        active    = true
+      }
+      block_release_bundle_distribution  = true
+      fail_build                         = true
+      notify_watch_recipients            = true
+      notify_deployer                    = true
+      create_ticket_enabled              = false  // set to true only if Jira integration is enabled
+      build_failure_grace_period_in_days = 5      // use only if fail_build is enabled
     }
   }
+}
 
-  resources {
-    type       = "repository"
-    name       = "npm-remote"
-    bin_mgr_id = "default"
-    repo_type  = "remote"
+resource "xray_license_policy" "license1" {
+  name        = "test-license-policy-allowed-${random_id.randid.dec}"
+  description = "License policy, allow certain licenses"
+  type        = "license"
+  rules {
+    name     = "License_rule"
+    priority = 1
+    criteria {
+      allowed_licenses         = ["Apache-1.0", "Apache-2.0"]
+      allow_unknown            = false
+      multi_license_permissive = true
+    }
+    actions {
+      webhooks = []
+      mails    = ["test@email.com"]
+      block_download {
+        unscanned = true
+        active    = true
+      }
+      block_release_bundle_distribution  = false
+      fail_build                         = true
+      notify_watch_recipients            = true
+      notify_deployer                    = true
+      create_ticket_enabled              = false      // set to true only if Jira integration is enabled
+      custom_severity                    = "High"
+      build_failure_grace_period_in_days = 5          // use only if fail_build is enabled
 
-    filters {
-      type  = "package-type"
-      value = "Npm"
     }
   }
+}
 
-  assigned_policies {
-    name = xray_policy.test.name
-    type = "security"
+resource "xray_license_policy" "license2" {
+  name        = "test-license-policy-banned-${random_id.randid.dec}"
+  description = "License policy, block certain licenses"
+  type        = "license"
+  rules {
+    name     = "License_rule"
+    priority = 1
+    criteria {
+      banned_licenses          = ["Apache-3.0", "Apache-4.0"]
+      allow_unknown            = false
+      multi_license_permissive = false
+    }
+    actions {
+      webhooks = []
+      mails    = ["test@email.com"]
+      block_download {
+        unscanned = true
+        active    = true
+      }
+      block_release_bundle_distribution  = false
+      fail_build                         = true
+      notify_watch_recipients            = true
+      notify_deployer                    = true
+      create_ticket_enabled              = false      // set to true only if Jira integration is enabled
+      custom_severity                    = "Medium"
+      build_failure_grace_period_in_days = 5          // use only if fail_build is enabled
+
+    }
   }
-}
+}
\ No newline at end of file


Test patch:
diff --git a/TFproviderTest.yml b/TFproviderTest.yml
index c0b8127b..94fb1f1b 100644
--- a/TFproviderTest.yml
+++ b/TFproviderTest.yml
@@ -3,7 +3,7 @@ resources:
     type: GitRepo
     configuration:
       gitProvider: Partnership_GitHub
-      path: jfrog/terraform-provider-artifactory # if path is modified, change the name as well, per Pipelines doc
+      path: jfrog/terraform-provider-xray # if path is modified, change the name as well, per Pipelines doc
       branches:
         include: master
       buildOn:
diff --git a/pkg/xray/provider_test.go b/pkg/xray/provider_test.go
index d0b5155a..bf549381 100644
--- a/pkg/xray/provider_test.go
+++ b/pkg/xray/provider_test.go
@@ -3,7 +3,6 @@ package xray
 import (
 	"context"
 	"github.com/go-resty/resty/v2"
-	"io/ioutil"
 	"os"
 	"testing"
 
@@ -14,7 +13,7 @@ import (
 var testAccProviders = func() map[string]func() (*schema.Provider, error) {
 	provider := Provider()
 	return map[string]func() (*schema.Provider, error){
-		"artifactory": func() (*schema.Provider, error) {
+		"xray": func() (*schema.Provider, error) {
 			return provider, nil
 		},
 	}
@@ -26,18 +25,6 @@ func TestProvider(t *testing.T) {
 	}
 }
 
-func TestProvider_impl(t *testing.T) {
-	var _ = Provider()
-}
-func uploadTestFile(client *resty.Client, localPath, remotePath, contentType string) error {
-	body, err := ioutil.ReadFile(localPath)
-	if err != nil {
-		return err
-	}
-	uri := "/artifactory/" + remotePath
-	_, err = client.R().SetBody(body).SetHeader("Content-Type", contentType).Put(uri)
-	return err
-}
 func getTestResty(t *testing.T) *resty.Client {
 	if v := os.Getenv("ARTIFACTORY_URL"); v == "" {
 		t.Fatal("ARTIFACTORY_URL must be set for acceptance tests")
@@ -62,7 +49,7 @@ func testAccPreCheck(t *testing.T) {
 		t.Fatal(err)
 	}
 	ctx := context.Background()
-	provider, _ := testAccProviders["artifactory"]()
+	provider, _ := testAccProviders["xray"]()
 	oldErr := provider.Configure(ctx, terraform.NewResourceConfigRaw(nil))
 	if oldErr != nil {
 		t.Fatal(oldErr)
diff --git a/pkg/xray/resource_xray_license_policy_test.go b/pkg/xray/resource_xray_license_policy_test.go
new file mode 100644
index 00000000..0b6c9dac
--- /dev/null
+++ b/pkg/xray/resource_xray_license_policy_test.go
@@ -0,0 +1,353 @@
+package xray
+
+import (
+	"fmt"
+	"net/http"
+	"regexp"
+	"testing"
+
+	"github.com/go-resty/resty/v2"
+
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
+)
+
+var tempStructLicense = map[string]string{
+	"resource_name":                     "",
+	"policy_name":                       "terraform-license-policy",
+	"policy_description":                "policy created by xray acceptance tests",
+	"rule_name":                         "test-license-rule",
+	"license_0":                         "Apache-1.0",
+	"license_1":                         "Apache-2.0",
+	"mails_0":                           "test0@email.com",
+	"mails_1":                           "test1@email.com",
+	"allow_unknown":                     "true",
+	"multi_license_permissive":          "false",
+	"block_release_bundle_distribution": "true",
+	"fail_build":                        "true",
+	"notify_watch_recipients":           "true",
+	"notify_deployer":                   "true",
+	"create_ticket_enabled":             "false",
+	"custom_severity":                   "High",
+	"grace_period_days":                 "5",
+	"block_unscanned":                   "true",
+	"block_active":                      "true",
+}
+
+// License policy criteria are different from the security policy criteria
+// Test will try to post a new license policy with incorrect body of security policy
+// with specified cvss_range. The function expandLicenseCriteria will ignore all the
+// fields except of "allow_unknown", "banned_licenses" and "allowed_licenses" if the Policy type is "license"
+func TestAccLicensePolicy_badLicenseCriteria(t *testing.T) {
+	_, fqrn, resourceName := mkNames("policy-", "xray_license_policy")
+	policyName := "terraform-license-policy-1"
+	policyDesc := "policy created by xray acceptance tests"
+	ruleName := "test-license-rule-1"
+	rangeTo := 5
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckLicensePolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config:      testAccXrayLicensePolicy_badLicense(resourceName, policyName, policyDesc, ruleName, rangeTo),
+				ExpectError: regexp.MustCompile("\"error\":\"Rule " + ruleName + " has empty criteria\""),
+			},
+		},
+	})
+}
+
+// This test will try to create a license policy with failure grace period set, but without fail build turned on
+func TestAccLicensePolicy_badGracePeriod(t *testing.T) {
+	_, fqrn, resourceName := mkNames("policy-", "xray_license_policy")
+	tempStruct := make(map[string]string)
+	copyStringMap(tempStructLicense, tempStruct)
+
+	tempStruct["resource_name"] = resourceName
+	tempStruct["policy_name"] = "terraform-security-policy-2"
+	tempStruct["rule_name"] = "test-license-rule-2"
+	tempStruct["fail_build"] = "false"
+	tempStruct["grace_period_days"] = "5"
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckLicensePolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config:      executeTemplate(fqrn, licensePolicyAllowed, tempStruct),
+				ExpectError: regexp.MustCompile("Rule " + tempStruct["rule_name"] + " has failure grace period without fail build"),
+			},
+		},
+	})
+}
+
+func TestAccLicensePolicy_createAllowedLic(t *testing.T) {
+	_, fqrn, resourceName := mkNames("policy-", "xray_license_policy")
+	tempStruct := make(map[string]string)
+	copyStringMap(tempStructLicense, tempStruct)
+
+	tempStruct["resource_name"] = resourceName
+	tempStruct["policy_name"] = "terraform-license-policy-3"
+	tempStruct["rule_name"] = "test-license-rule-3"
+	tempStruct["multi_license_permissive"] = "true"
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckLicensePolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config: executeTemplate(fqrn, licensePolicyAllowed, tempStruct),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(fqrn, "name", tempStruct["policy_name"]),
+					resource.TestCheckResourceAttr(fqrn, "description", tempStruct["policy_description"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.name", tempStruct["rule_name"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.allow_unknown", tempStruct["allow_unknown"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.multi_license_permissive", tempStruct["multi_license_permissive"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.allowed_licenses.0", tempStruct["license_0"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.allowed_licenses.1", tempStruct["license_1"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.mails.0", tempStruct["mails_0"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.mails.1", tempStruct["mails_1"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_release_bundle_distribution", tempStruct["block_release_bundle_distribution"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.fail_build", tempStruct["fail_build"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_watch_recipients", tempStruct["notify_watch_recipients"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_deployer", tempStruct["notify_deployer"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.create_ticket_enabled", tempStruct["create_ticket_enabled"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.build_failure_grace_period_in_days", tempStruct["grace_period_days"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.active", tempStruct["block_active"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.unscanned", tempStruct["block_unscanned"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.custom_severity", tempStruct["custom_severity"]),
+				),
+			},
+		},
+	})
+}
+
+func TestAccLicensePolicy_createBannedLic(t *testing.T) {
+	_, fqrn, resourceName := mkNames("policy-", "xray_license_policy")
+	tempStruct := make(map[string]string)
+	copyStringMap(tempStructLicense, tempStruct)
+
+	tempStruct["resource_name"] = resourceName
+	tempStruct["policy_name"] = "terraform-license-policy-4"
+	tempStruct["rule_name"] = "test-license-rule-4"
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckLicensePolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config: executeTemplate(fqrn, licensePolicyBanned, tempStruct),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(fqrn, "name", tempStruct["policy_name"]),
+					resource.TestCheckResourceAttr(fqrn, "description", tempStruct["policy_description"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.name", tempStruct["rule_name"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.allow_unknown", tempStruct["allow_unknown"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.multi_license_permissive", tempStruct["multi_license_permissive"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.banned_licenses.0", tempStruct["license_0"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.banned_licenses.1", tempStruct["license_1"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.mails.0", tempStruct["mails_0"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.mails.1", tempStruct["mails_1"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_release_bundle_distribution", tempStruct["block_release_bundle_distribution"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.fail_build", tempStruct["fail_build"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_watch_recipients", tempStruct["notify_watch_recipients"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_deployer", tempStruct["notify_deployer"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.create_ticket_enabled", tempStruct["create_ticket_enabled"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.build_failure_grace_period_in_days", tempStruct["grace_period_days"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.active", tempStruct["block_active"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.unscanned", tempStruct["block_unscanned"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.custom_severity", tempStruct["custom_severity"]),
+				),
+			},
+		},
+	})
+}
+
+func TestAccLicensePolicy_createMultiLicensePermissiveFalse(t *testing.T) {
+	_, fqrn, resourceName := mkNames("policy-", "xray_license_policy")
+	tempStruct := make(map[string]string)
+	copyStringMap(tempStructLicense, tempStruct)
+
+	tempStruct["resource_name"] = resourceName
+	tempStruct["policy_name"] = "terraform-license-policy-5"
+	tempStruct["rule_name"] = "test-license-rule-5"
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckLicensePolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config: executeTemplate(fqrn, licensePolicyBanned, tempStruct),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(fqrn, "name", tempStruct["policy_name"]),
+					resource.TestCheckResourceAttr(fqrn, "description", tempStruct["policy_description"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.name", tempStruct["rule_name"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.allow_unknown", tempStruct["allow_unknown"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.multi_license_permissive", tempStruct["multi_license_permissive"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.banned_licenses.0", tempStruct["license_0"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.banned_licenses.1", tempStruct["license_1"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.mails.0", tempStruct["mails_0"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.mails.1", tempStruct["mails_1"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_release_bundle_distribution", tempStruct["block_release_bundle_distribution"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.fail_build", tempStruct["fail_build"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_watch_recipients", tempStruct["notify_watch_recipients"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_deployer", tempStruct["notify_deployer"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.create_ticket_enabled", tempStruct["create_ticket_enabled"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.build_failure_grace_period_in_days", tempStruct["grace_period_days"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.active", tempStruct["block_active"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.unscanned", tempStruct["block_unscanned"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.custom_severity", tempStruct["custom_severity"]),
+				),
+			},
+		},
+	})
+}
+
+func TestAccLicensePolicy_createBlockFalse(t *testing.T) {
+	_, fqrn, resourceName := mkNames("policy-", "xray_license_policy")
+	tempStruct := make(map[string]string)
+	copyStringMap(tempStructLicense, tempStruct)
+
+	tempStruct["resource_name"] = resourceName
+	tempStruct["policy_name"] = "terraform-license-policy-6"
+	tempStruct["rule_name"] = "test-license-rule-6"
+	tempStruct["block_unscanned"] = "true"
+	tempStruct["block_active"] = "true"
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckLicensePolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config: executeTemplate(fqrn, licensePolicyBanned, tempStruct),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(fqrn, "name", tempStruct["policy_name"]),
+					resource.TestCheckResourceAttr(fqrn, "description", tempStruct["policy_description"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.name", tempStruct["rule_name"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.allow_unknown", tempStruct["allow_unknown"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.multi_license_permissive", tempStruct["multi_license_permissive"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.banned_licenses.0", tempStruct["license_0"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.banned_licenses.1", tempStruct["license_1"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.mails.0", tempStruct["mails_0"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.mails.1", tempStruct["mails_1"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_release_bundle_distribution", tempStruct["block_release_bundle_distribution"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.fail_build", tempStruct["fail_build"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_watch_recipients", tempStruct["notify_watch_recipients"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_deployer", tempStruct["notify_deployer"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.create_ticket_enabled", tempStruct["create_ticket_enabled"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.build_failure_grace_period_in_days", tempStruct["grace_period_days"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.active", tempStruct["block_active"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.unscanned", tempStruct["block_unscanned"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.custom_severity", tempStruct["custom_severity"]),
+				),
+			},
+		},
+	})
+}
+
+func testAccCheckLicensePolicyDestroy(id string) func(*terraform.State) error {
+	return func(s *terraform.State) error {
+		rs, ok := s.RootModule().Resources[id]
+		if !ok {
+			return fmt.Errorf("error: Resource id [%s] not found", id)
+		}
+		provider, _ := testAccProviders["xray"]()
+		_, resp, _ := getPolicy(rs.Primary.ID, provider.Meta().(*resty.Client))
+
+		if resp.StatusCode() == http.StatusOK {
+			return fmt.Errorf("error: Policy %s still exists", rs.Primary.ID)
+		}
+		return nil
+	}
+}
+
+func testAccXrayLicensePolicy_badLicense(resourceName, name, description, ruleName string, rangeTo int) string {
+	return fmt.Sprintf(`
+resource "xray_security_policy" "%s" {
+	name = "%s"
+	description = "%s"
+	type = "license"
+	rules {
+		name = "%s"
+		priority = 1
+		criteria {
+			cvss_range {
+				from = 1
+				to = %d
+			}
+		}
+		actions {
+			block_download {
+				unscanned = true
+				active = true
+			}
+		}
+	}
+}
+`, resourceName, name, description, ruleName, rangeTo)
+}
+
+const licensePolicyAllowed = `resource "xray_license_policy" "{{ .resource_name }}" {
+	name = "{{ .policy_name }}"
+	description = "{{ .policy_description }}"
+	type = "license"
+	rules {
+		name = "{{ .rule_name }}"
+		priority = 1
+		criteria {	
+          allowed_licenses = ["{{ .license_0 }}","{{ .license_1 }}"]
+          allow_unknown = {{ .allow_unknown }}
+          multi_license_permissive = {{ .multi_license_permissive }}
+		}
+		actions {
+          webhooks = []
+          mails = ["{{ .mails_0 }}", "{{ .mails_1 }}"]
+          block_download {
+				unscanned = {{ .block_unscanned }}
+				active = {{ .block_active }}
+          }
+          block_release_bundle_distribution = {{ .block_release_bundle_distribution }}
+          fail_build = {{ .fail_build }}
+          notify_watch_recipients = {{ .notify_watch_recipients }}
+          notify_deployer = {{ .notify_deployer }}
+          create_ticket_enabled = {{ .create_ticket_enabled }}           
+          custom_severity = "{{ .custom_severity }}"
+          build_failure_grace_period_in_days = {{ .grace_period_days }}  
+		}
+	}
+}`
+
+const licensePolicyBanned = `resource "xray_license_policy" "{{ .resource_name }}" {
+	name = "{{ .policy_name }}"
+	description = "{{ .policy_description }}"
+	type = "license"
+	rules {
+		name = "{{ .rule_name }}"
+		priority = 1
+		criteria {	
+          banned_licenses = ["{{ .license_0 }}","{{ .license_1 }}"]
+          allow_unknown = {{ .allow_unknown }}
+          multi_license_permissive = {{ .multi_license_permissive }}
+		}
+		actions {
+          webhooks = []
+          mails = ["{{ .mails_0 }}", "{{ .mails_1 }}"]
+          block_download {
+				unscanned = {{ .block_unscanned }}
+				active = {{ .block_active }}
+          }
+          block_release_bundle_distribution = {{ .block_release_bundle_distribution }}
+          fail_build = {{ .fail_build }}
+          notify_watch_recipients = {{ .notify_watch_recipients }}
+          notify_deployer = {{ .notify_deployer }}
+          create_ticket_enabled = {{ .create_ticket_enabled }}           
+          custom_severity = "{{ .custom_severity }}"
+          build_failure_grace_period_in_days = {{ .grace_period_days }}  
+		}
+	}
+}`
diff --git a/pkg/xray/resource_xray_policy_test.go b/pkg/xray/resource_xray_policy_test.go
deleted file mode 100644
index e144106f..00000000
--- a/pkg/xray/resource_xray_policy_test.go
+++ /dev/null
@@ -1,452 +0,0 @@
-package xray
-
-import (
-	"fmt"
-	"net/http"
-	"regexp"
-	"testing"
-
-	"github.com/go-resty/resty/v2"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
-	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
-)
-
-// Test was temporarily removed from the test suite
-//func TestAccPolicy_basic(t *testing.T) {
-//	policyName := "terraform-test-policy"
-//	policyDesc := "policy created by xray acceptance tests"
-//	ruleName := "test-security-rule"
-//	resourceName := "xray_policy.test"
-//
-//	resource.Test(t, resource.TestCase{
-//		PreCheck:     func() { testAccPreCheck(t) },
-//		CheckDestroy: testAccCheckPolicyDestroy,
-//		Providers:    testAccProviders,
-//		Steps: []resource.TestStep{
-//			{
-//				Config: testAccXrayPolicyBasic(policyName, policyDesc, ruleName),
-//				Check: resource.ComposeTestCheckFunc(
-//					resource.TestCheckResourceAttr(resourceName, "name", policyName),
-//					resource.TestCheckResourceAttr(resourceName, "description", policyDesc),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.name", ruleName),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.priority", "1"),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.criteria.0.min_severity", "High"),
-//				),
-//			},
-//			{
-//				ResourceName:      resourceName,
-//				ImportState:       true,
-//				ImportStateVerify: false, // TODO: figure out why this doesn't work
-//			},
-//		},
-//	})
-//}
-
-// Test was temporarily removed from the test suite
-//func TestAccPolicy_cvssRange(t *testing.T) {
-//	policyName := "terraform-test-policy"
-//	policyDesc := "policy created by xray acceptance tests"
-//	ruleName := "test-security-rule"
-//	rangeTo := 4
-//	updatedRangeTo := 2
-//	resourceName := "xray_policy.test"
-//
-//	resource.Test(t, resource.TestCase{
-//		PreCheck:     func() { testAccPreCheck(t) },
-//		CheckDestroy: testAccCheckPolicyDestroy,
-//		Providers:    testAccProviders,
-//		Steps: []resource.TestStep{
-//			{
-//				Config: testAccXrayPolicyCVSSRange(policyName, policyDesc, ruleName, rangeTo),
-//				Check: resource.ComposeTestCheckFunc(
-//					resource.TestCheckResourceAttr(resourceName, "name", policyName),
-//					resource.TestCheckResourceAttr(resourceName, "description", policyDesc),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.name", ruleName),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.priority", "1"),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.criteria.0.cvss_range.0.to", fmt.Sprintf("%d", rangeTo)),
-//				),
-//			},
-//			{
-//				ResourceName:      resourceName,
-//				ImportState:       true,
-//				ImportStateVerify: false,
-//			},
-//			{
-//				Config: testAccXrayPolicyCVSSRange(policyName, policyDesc, ruleName, updatedRangeTo),
-//				Check: resource.ComposeTestCheckFunc(
-//					resource.TestCheckResourceAttr(resourceName, "name", policyName),
-//					resource.TestCheckResourceAttr(resourceName, "description", policyDesc),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.name", ruleName),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.priority", "1"),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.criteria.0.cvss_range.0.to", fmt.Sprintf("%d", updatedRangeTo)),
-//				),
-//			},
-//		},
-//	})
-//}
-
-// Test was temporarily removed from the test suite
-//func TestAccPolicy_allActions(t *testing.T) {
-//	policyName := "terraform-test-policy"
-//	policyDesc := "policy created by xray acceptance tests"
-//	ruleName := "test-security-rule"
-//	actionMail := "test@example.com"
-//	updatedDesc := "updated policy description"
-//	updatedRuleName := "test-updated-rule"
-//	updatedMail := "test2@example.com"
-//	resourceName := "xray_policy.test"
-//
-//	resource.Test(t, resource.TestCase{
-//		PreCheck:     func() { testAccPreCheck(t) },
-//		CheckDestroy: testAccCheckPolicyDestroy,
-//		Providers:    testAccProviders,
-//		Steps: []resource.TestStep{
-//			{
-//				Config: testAccXrayPolicyAllActions(policyName, policyDesc, ruleName, actionMail),
-//				Check: resource.ComposeTestCheckFunc(
-//					resource.TestCheckResourceAttr(resourceName, "name", policyName),
-//					resource.TestCheckResourceAttr(resourceName, "description", policyDesc),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.name", ruleName),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.priority", "1"),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.criteria.0.min_severity", "High"),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.actions.0.fail_build", "true"),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.actions.0.mails.0", actionMail),
-//				),
-//			},
-//			{
-//				ResourceName:      resourceName,
-//				ImportState:       true,
-//				ImportStateVerify: false,
-//			},
-//			{
-//				Config: testAccXrayPolicyAllActions(policyName, updatedDesc, updatedRuleName, updatedMail),
-//				Check: resource.ComposeTestCheckFunc(
-//					resource.TestCheckResourceAttr(resourceName, "name", policyName),
-//					resource.TestCheckResourceAttr(resourceName, "description", updatedDesc),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.name", updatedRuleName),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.priority", "1"),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.criteria.0.min_severity", "High"),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.actions.0.fail_build", "true"),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.actions.0.mails.0", updatedMail),
-//				),
-//			},
-//		},
-//	})
-//}
-// Test was temporarily removed from the test suite
-//func TestAccPolicy_licenseCriteria(t *testing.T) {
-//	policyName := "terraform-test-policy"
-//	policyDesc := "policy created by xray acceptance tests"
-//	ruleName := "test-security-rule"
-//	allowedLicense := "BSD-4-Clause"
-//	bannedLicense1 := "0BSD"
-//	bannedLicense2 := "diffmark"
-//	resourceName := "xray_policy.test"
-//
-//	resource.Test(t, resource.TestCase{
-//		PreCheck:     func() { testAccPreCheck(t) },
-//		CheckDestroy: testAccCheckPolicyDestroy,
-//		Providers:    testAccProviders,
-//		Steps: []resource.TestStep{
-//			{
-//				Config: testAccXrayPolicyLicense(policyName, policyDesc, ruleName, allowedLicense),
-//				Check: resource.ComposeTestCheckFunc(
-//					resource.TestCheckResourceAttr(resourceName, "name", policyName),
-//					resource.TestCheckResourceAttr(resourceName, "description", policyDesc),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.name", ruleName),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.priority", "1"),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.criteria.0.allowed_licenses.0", allowedLicense),
-//				),
-//			},
-//			{
-//				ResourceName:      resourceName,
-//				ImportState:       true,
-//				ImportStateVerify: false,
-//			},
-//			{
-//				Config: testAccXrayPolicyLicenseBanned(policyName, policyDesc, ruleName, bannedLicense1, bannedLicense2),
-//				Check: resource.ComposeTestCheckFunc(
-//					resource.TestCheckResourceAttr(resourceName, "name", policyName),
-//					resource.TestCheckResourceAttr(resourceName, "description", policyDesc),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.name", ruleName),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.priority", "1"),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.criteria.0.banned_licenses.0", bannedLicense1),
-//					resource.TestCheckResourceAttr(resourceName, "rules.0.criteria.0.banned_licenses.1", bannedLicense2),
-//				),
-//			},
-//		},
-//	})
-//}
-
-func TestAccPolicy_badLicenseCriteria(t *testing.T) {
-	policyName := "terraform-test-policy"
-	policyDesc := "policy created by xray acceptance tests"
-	ruleName := "test-security-rule"
-	rangeTo := 4
-
-	resource.Test(t, resource.TestCase{
-		PreCheck:          func() { testAccPreCheck(t) },
-		CheckDestroy:      testAccCheckPolicyDestroy,
-		ProviderFactories: testAccProviders,
-		Steps: []resource.TestStep{
-			{
-				Config:      testAccXrayPolicy_badLicense(policyName, policyDesc, ruleName, rangeTo),
-				ExpectError: regexp.MustCompile("min_severity and cvvs_range are not supported with license policies"),
-			},
-		},
-	})
-}
-
-func TestAccPolicy_badSecurityCriteria(t *testing.T) {
-	policyName := "terraform-test-policy"
-	policyDesc := "policy created by xray acceptance tests"
-	ruleName := "test-security-rule"
-	allowedLicense := "BSD-4-Clause"
-
-	resource.Test(t, resource.TestCase{
-		PreCheck:          func() { testAccPreCheck(t) },
-		CheckDestroy:      testAccCheckPolicyDestroy,
-		ProviderFactories: testAccProviders,
-		Steps: []resource.TestStep{
-			{
-				Config:      testAccXrayPolicy_badSecurity(policyName, policyDesc, ruleName, allowedLicense),
-				ExpectError: regexp.MustCompile("allow_unknown, banned_licenses, and allowed_licenses are not supported with security policies"),
-			},
-		},
-	})
-}
-
-// This should be uncommented when someone figures out how to deal with this (see comment in expandActions in the provider)
-/*func TestAccPolicy_missingBlockDownloads(t *testing.T) {
-	policyName   := "terraform-test-policy"
-	policyDesc   := "policy created by xray acceptance tests"
-	ruleName     := "test-security-rule"
-	resourceName := "xray_policy.test"
-
-	resource.Test(t, resource.TestCase{
-		PreCheck:     func() { testAccPreCheck(t) },
-		CheckDestroy: testAccCheckPolicyDestroy,
-		Providers:    testAccProviders,
-		Steps: []resource.TestStep{
-			{
-				Config: testAccXrayPolicy_missingBlockDownloads(policyName, policyDesc, ruleName),
-				Check: resource.ComposeTestCheckFunc(
-					resource.TestCheckResourceAttr(resourceName, "name", policyName),
-					resource.TestCheckResourceAttr(resourceName, "description", policyDesc),
-					resource.TestCheckResourceAttr(resourceName, "rules.0.name", ruleName),
-					resource.TestCheckResourceAttr(resourceName, "rules.0.priority", "1"),
-				),
-			},
-			{
-				ResourceName:      resourceName,
-				ImportState:       true,
-				ImportStateVerify: false,
-			},
-		},
-	})
-}*/
-
-func testAccCheckPolicyDestroy(s *terraform.State) error {
-
-	for _, rs := range s.RootModule().Resources {
-		if rs.Type == "xray_policy" {
-			provider, _ := testAccProviders["artifactory"]()
-			policy, resp, err := getPolicy(rs.Primary.ID, provider.Meta().(*resty.Client))
-
-			if err != nil {
-				if resp != nil {
-					if resp.StatusCode() == http.StatusInternalServerError &&
-						err.Error() == fmt.Sprintf("{\"error\":\"Failed to find Policy %s\"}", rs.Primary.ID) {
-						continue
-					}
-					if resp.StatusCode() == http.StatusNotFound {
-						continue
-					}
-				}
-				return err
-			}
-			return fmt.Errorf("error: Policy %s still exists %s", rs.Primary.ID, *policy.Name)
-		}
-	}
-	return nil
-}
-
-func testAccXrayPolicyBasic(name, description, ruleName string) string {
-	return fmt.Sprintf(`
-		resource "xray_policy" "test" {
-			name  = "%s"
-			description = "%s"
-			type = "security"
-	
-			rules {
-				name = "%s"
-				priority = 1
-				criteria {
-					min_severity = "High"
-				}
-				actions {
-					block_download {
-						unscanned = true
-						active = true
-					}
-				}
-			}
-		}
-`, name, description, ruleName)
-}
-
-func testAccXrayPolicyCVSSRange(name, description, ruleName string, rangeTo int) string {
-	return fmt.Sprintf(`
-		resource "xray_policy" "test" {
-			name  = "%s"
-			description = "%s"
-			type = "security"
-		
-			rules {
-				name = "%s"
-				priority = 1
-				criteria {
-					cvss_range {
-						from = 1
-						to = %d
-					}
-				}
-				actions {
-					block_download {
-						unscanned = true
-						active = true
-					}
-				}
-			}
-		}
-`, name, description, ruleName, rangeTo)
-}
-
-func testAccXrayPolicyAllActions(name, description, ruleName, email string) string {
-	// Except for webhooks, because the API won't let you test with junk urls: Error: {"error":"Rule test-security-rule triggers an unrecognized webhook https://example.com"}
-	return fmt.Sprintf(`
-		resource "xray_policy" "test" {
-			name  = "%s"
-			description = "%s"
-			type = "security"
-		
-			rules {
-				name = "%s"
-				priority = 1
-				criteria {
-					min_severity = "High"
-				}
-				actions {
-					fail_build = true
-					block_download {
-						unscanned = false
-						active = false
-					}
-					mails = ["%s"]
-					custom_severity = "High"
-				}
-			}
-		}
-`, name, description, ruleName, email)
-}
-
-func testAccXrayPolicyLicense(name, description, ruleName, allowedLicense string) string {
-	return fmt.Sprintf(`
-		resource "xray_policy" "test" {
-			name = "%s"
-			description = "%s"
-			type = "license"
-		
-			rules {
-				name = "%s"
-				priority = 1
-				criteria {
-					allow_unknown = true
-					allowed_licenses = ["%s"]
-				}
-				actions {
-					block_download {
-						unscanned = true
-						active = true
-					}
-				}
-	}
-}
-`, name, description, ruleName, allowedLicense)
-}
-
-func testAccXrayPolicyLicenseBanned(name, description, ruleName, bannedLicense1, bannedLicense2 string) string {
-	return fmt.Sprintf(`
-		resource "xray_policy" "test" {
-			name = "%s"
-			description = "%s"
-			type = "license"
-		
-			rules {
-				name = "%s"
-				priority = 1
-				criteria {
-					allow_unknown = true
-					banned_licenses = ["%s", "%s"]
-				}
-				actions {
-					block_download {
-						unscanned = true
-						active = true
-					}
-				}
-			}
-		}
-`, name, description, ruleName, bannedLicense1, bannedLicense2)
-}
-
-func testAccXrayPolicy_badLicense(name, description, ruleName string, rangeTo int) string {
-	return fmt.Sprintf(`
-resource "xray_policy" "test" {
-	name = "%s"
-	description = "%s"
-	type = "license"
-	rules {
-		name = "%s"
-		priority = 1
-		criteria {
-			cvss_range {
-				from = 1
-				to = %d
-			}
-		}
-		actions {
-			block_download {
-				unscanned = true
-				active = true
-			}
-		}
-	}
-}
-`, name, description, ruleName, rangeTo)
-}
-
-func testAccXrayPolicy_badSecurity(name, description, ruleName, allowedLicense string) string {
-	return fmt.Sprintf(`
-resource "xray_policy" "test" {
-	name = "%s"
-	description = "%s"
-	type = "security"
-	rules {
-		name = "%s"
-		priority = 1
-		criteria {
-			allow_unknown = true
-			allowed_licenses = ["%s"]
-		}
-		actions {
-			block_download {
-				unscanned = true
-				active = true
-			}
-		}
-	}
-}
-`, name, description, ruleName, allowedLicense)
-}
diff --git a/pkg/xray/resource_xray_security_policy_test.go b/pkg/xray/resource_xray_security_policy_test.go
new file mode 100644
index 00000000..29858bb5
--- /dev/null
+++ b/pkg/xray/resource_xray_security_policy_test.go
@@ -0,0 +1,435 @@
+package xray
+
+import (
+	"fmt"
+	"net/http"
+	"regexp"
+	"strconv"
+	"testing"
+
+	"github.com/go-resty/resty/v2"
+
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
+)
+
+var tempStructSecurity = map[string]string{
+	"resource_name":                     "",
+	"policy_name":                       "terraform-security-policy",
+	"policy_description":                "policy created by xray acceptance tests",
+	"rule_name":                         "test-security-rule",
+	"cvss_from":                         "1",    // conflicts with min_severity
+	"cvss_to":                           "5",    // conflicts with min_severity
+	"min_severity":                      "High", // conflicts with cvss_from/cvss_to
+	"block_release_bundle_distribution": "true",
+	"fail_build":                        "true",
+	"notify_watch_recipients":           "true",
+	"notify_deployer":                   "true",
+	"create_ticket_enabled":             "false",
+	"grace_period_days":                 "5",
+	"block_unscanned":                   "true",
+	"block_active":                      "true",
+}
+
+// Teh test will try to create a security policy with the type of "license"
+// The Policy criteria will be ignored in this case
+func TestAccSecurityPolicy_badTypeInSecurityPolicy(t *testing.T) {
+	policyName := "terraform-security-policy-1"
+	policyDesc := "policy created by xray acceptance tests"
+	ruleName := "test-security-rule-1"
+	rangeTo := 5
+	resourceName := "policy-" + strconv.Itoa(randomInt())
+	fqrn := "xray_security_policy." + resourceName
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckSecurityPolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config:      testAccXraySecurityPolicy_badSecurityType(policyName, policyDesc, ruleName, rangeTo),
+				ExpectError: regexp.MustCompile("Rule " + ruleName + " has empty criteria"),
+			},
+		},
+	})
+}
+
+// The test will try to use "allowed_licenses" in the security policy criteria
+// That field is acceptable only in license policy. No API call, expected to fail on the TF resource verification
+func TestAccSecurityPolicy_badSecurityCriteria(t *testing.T) {
+	policyName := "terraform-security-policy-2"
+	policyDesc := "policy created by xray acceptance tests"
+	ruleName := "test-security-rule-2"
+	allowedLicense := "BSD-4-Clause"
+	resourceName := "policy-" + strconv.Itoa(randomInt())
+	fqrn := "xray_security_policy." + resourceName
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckSecurityPolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config:      testAccXraySecurityPolicy_badSecurity(policyName, policyDesc, ruleName, allowedLicense),
+				ExpectError: regexp.MustCompile("An argument named \"allow_unknown\" is not expected here."),
+			},
+		},
+	})
+}
+
+// This test will try to create a security policy with "build_failure_grace_period_in_days" set,
+// but with "fail_build" set to false, which conflicts with the field mentioned above.
+func TestAccSecurityPolicy_badGracePeriod(t *testing.T) {
+	_, fqrn, resourceName := mkNames("policy-", "xray_security_policy")
+	tempStruct := make(map[string]string)
+	copyStringMap(tempStructSecurity, tempStruct)
+
+	tempStruct["resource_name"] = resourceName
+	tempStruct["policy_name"] = "terraform-security-policy-3"
+	tempStruct["rule_name"] = "test-security-rule-3"
+	tempStruct["fail_build"] = "false"
+	tempStruct["grace_period_days"] = "5"
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckSecurityPolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config:      executeTemplate(fqrn, securityPolicyCVSS, tempStruct),
+				ExpectError: regexp.MustCompile("Rule " + tempStruct["rule_name"] + " has failure grace period without fail build"),
+			},
+		},
+	})
+}
+
+// CVSS criteria, block downloading of unscanned and active
+func TestAccSecurityPolicy_createBlockDownloadTrueCVSS(t *testing.T) {
+	_, fqrn, resourceName := mkNames("policy-", "xray_security_policy")
+	tempStruct := make(map[string]string)
+	copyStringMap(tempStructSecurity, tempStruct)
+
+	tempStruct["resource_name"] = resourceName
+	tempStruct["policy_name"] = "terraform-security-policy-4"
+	tempStruct["rule_name"] = "test-security-rule-4"
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckSecurityPolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config: executeTemplate(fqrn, securityPolicyCVSS, tempStruct),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(fqrn, "name", tempStruct["policy_name"]),
+					resource.TestCheckResourceAttr(fqrn, "description", tempStruct["policy_description"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.name", tempStruct["rule_name"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.cvss_range.0.from", tempStruct["cvss_from"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.cvss_range.0.to", tempStruct["cvss_to"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_release_bundle_distribution", tempStruct["block_release_bundle_distribution"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.fail_build", tempStruct["fail_build"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_watch_recipients", tempStruct["notify_watch_recipients"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_deployer", tempStruct["notify_deployer"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.create_ticket_enabled", tempStruct["create_ticket_enabled"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.build_failure_grace_period_in_days", tempStruct["grace_period_days"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.active", tempStruct["block_active"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.unscanned", tempStruct["block_unscanned"]),
+				),
+			},
+		},
+	})
+}
+
+// CVSS criteria, allow downloading of unscanned and active
+func TestAccSecurityPolicy_createBlockDownloadFalseCVSS(t *testing.T) {
+	_, fqrn, resourceName := mkNames("policy-", "xray_security_policy")
+	tempStruct := make(map[string]string)
+	copyStringMap(tempStructSecurity, tempStruct)
+
+	tempStruct["resource_name"] = resourceName
+	tempStruct["policy_name"] = "terraform-security-policy-5"
+	tempStruct["rule_name"] = "test-security-rule-5"
+	tempStruct["block_unscanned"] = "false"
+	tempStruct["block_active"] = "false"
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckSecurityPolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config: executeTemplate(fqrn, securityPolicyCVSS, tempStruct),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(fqrn, "name", tempStruct["policy_name"]),
+					resource.TestCheckResourceAttr(fqrn, "description", tempStruct["policy_description"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.name", tempStruct["rule_name"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.cvss_range.0.from", tempStruct["cvss_from"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.cvss_range.0.to", tempStruct["cvss_to"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_release_bundle_distribution", tempStruct["block_release_bundle_distribution"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.fail_build", tempStruct["fail_build"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_watch_recipients", tempStruct["notify_watch_recipients"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_deployer", tempStruct["notify_deployer"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.create_ticket_enabled", tempStruct["create_ticket_enabled"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.build_failure_grace_period_in_days", tempStruct["grace_period_days"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.active", tempStruct["block_active"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.unscanned", tempStruct["block_unscanned"]),
+				),
+			},
+		},
+	})
+}
+
+// Min severity criteria, block downloading of unscanned and active
+func TestAccSecurityPolicy_createBlockDownloadTrueMinSeverity(t *testing.T) {
+	_, fqrn, resourceName := mkNames("policy-", "xray_security_policy")
+	tempStruct := make(map[string]string)
+	copyStringMap(tempStructSecurity, tempStruct)
+
+	tempStruct["resource_name"] = resourceName
+	tempStruct["policy_name"] = "terraform-security-policy-6"
+	tempStruct["rule_name"] = "test-security-rule-6"
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckSecurityPolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config: executeTemplate(fqrn, securityPolicyMinSeverity, tempStruct),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(fqrn, "name", tempStruct["policy_name"]),
+					resource.TestCheckResourceAttr(fqrn, "description", tempStruct["policy_description"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.name", tempStruct["rule_name"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.min_severity", tempStruct["min_severity"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_release_bundle_distribution", tempStruct["block_release_bundle_distribution"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.fail_build", tempStruct["fail_build"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_watch_recipients", tempStruct["notify_watch_recipients"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_deployer", tempStruct["notify_deployer"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.create_ticket_enabled", tempStruct["create_ticket_enabled"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.build_failure_grace_period_in_days", tempStruct["grace_period_days"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.active", tempStruct["block_active"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.unscanned", tempStruct["block_unscanned"]),
+				),
+			},
+		},
+	})
+}
+
+// Min severity criteria, allow downloading of unscanned and active
+func TestAccSecurityPolicy_createBlockDownloadFalseMinSeverity(t *testing.T) {
+	_, fqrn, resourceName := mkNames("policy-", "xray_security_policy")
+	tempStruct := make(map[string]string)
+	copyStringMap(tempStructSecurity, tempStruct)
+
+	tempStruct["resource_name"] = resourceName
+	tempStruct["policy_name"] = "terraform-security-policy-7"
+	tempStruct["rule_name"] = "test-security-rule-7"
+	tempStruct["block_unscanned"] = "false"
+	tempStruct["block_active"] = "false"
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckSecurityPolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config: executeTemplate(fqrn, securityPolicyMinSeverity, tempStruct),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(fqrn, "name", tempStruct["policy_name"]),
+					resource.TestCheckResourceAttr(fqrn, "description", tempStruct["policy_description"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.name", tempStruct["rule_name"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.min_severity", tempStruct["min_severity"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_release_bundle_distribution", tempStruct["block_release_bundle_distribution"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.fail_build", tempStruct["fail_build"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_watch_recipients", tempStruct["notify_watch_recipients"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_deployer", tempStruct["notify_deployer"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.create_ticket_enabled", tempStruct["create_ticket_enabled"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.build_failure_grace_period_in_days", tempStruct["grace_period_days"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.active", tempStruct["block_active"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.unscanned", tempStruct["block_unscanned"]),
+				),
+			},
+		},
+	})
+}
+
+// CVSS criteria, use float values for CVSS range
+func TestAccSecurityPolicy_createCVSSFloat(t *testing.T) {
+	_, fqrn, resourceName := mkNames("policy-", "xray_security_policy")
+	tempStruct := make(map[string]string)
+	copyStringMap(tempStructSecurity, tempStruct)
+
+	tempStruct["resource_name"] = resourceName
+	tempStruct["policy_name"] = "terraform-security-policy-8"
+	tempStruct["rule_name"] = "test-security-rule-8"
+	tempStruct["cvss_from"] = "1.5"
+	tempStruct["cvss_to"] = "5.3"
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckSecurityPolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config: executeTemplate(fqrn, securityPolicyCVSS, tempStruct),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr(fqrn, "name", tempStruct["policy_name"]),
+					resource.TestCheckResourceAttr(fqrn, "description", tempStruct["policy_description"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.name", tempStruct["rule_name"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.cvss_range.0.from", tempStruct["cvss_from"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.criteria.0.cvss_range.0.to", tempStruct["cvss_to"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_release_bundle_distribution", tempStruct["block_release_bundle_distribution"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.fail_build", tempStruct["fail_build"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_watch_recipients", tempStruct["notify_watch_recipients"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.notify_deployer", tempStruct["notify_deployer"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.create_ticket_enabled", tempStruct["create_ticket_enabled"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.build_failure_grace_period_in_days", tempStruct["grace_period_days"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.active", tempStruct["block_active"]),
+					resource.TestCheckResourceAttr(fqrn, "rules.0.actions.0.block_download.0.unscanned", tempStruct["block_unscanned"]),
+				),
+			},
+		},
+	})
+}
+
+func TestAccSecurityPolicy_blockMismatchCVSS(t *testing.T) {
+	_, fqrn, resourceName := mkNames("policy-", "xray_security_policy")
+	tempStruct := make(map[string]string)
+	copyStringMap(tempStructSecurity, tempStruct)
+
+	tempStruct["resource_name"] = resourceName
+	tempStruct["policy_name"] = "terraform-security-policy-9"
+	tempStruct["rule_name"] = "test-security-rule-9"
+	tempStruct["block_unscanned"] = "true"
+	tempStruct["block_active"] = "false"
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:          func() { testAccPreCheck(t) },
+		CheckDestroy:      testAccCheckSecurityPolicyDestroy(fqrn),
+		ProviderFactories: testAccProviders,
+		Steps: []resource.TestStep{
+			{
+				Config: executeTemplate(fqrn, securityPolicyCVSS, tempStruct),
+				ExpectError: regexp.MustCompile("Rule " + tempStruct["rule_name"] +
+					" has block unscanned without block download"),
+			},
+		},
+	})
+}
+
+func testAccCheckSecurityPolicyDestroy(id string) func(*terraform.State) error {
+	return func(s *terraform.State) error {
+		rs, ok := s.RootModule().Resources[id]
+		if !ok {
+			return fmt.Errorf("error: Resource id [%s] not found", id)
+		}
+		provider, _ := testAccProviders["xray"]()
+		_, resp, _ := getPolicy(rs.Primary.ID, provider.Meta().(*resty.Client))
+
+		if resp.StatusCode() == http.StatusOK {
+			return fmt.Errorf("error: Policy %s still exists", rs.Primary.ID)
+		}
+		return nil
+	}
+}
+
+func testAccXraySecurityPolicy_badSecurityType(name, description, ruleName string, rangeTo int) string {
+	return fmt.Sprintf(`
+resource "xray_security_policy" "test" {
+	name = "%s"
+	description = "%s"
+	type = "license"
+	rules {
+		name = "%s"
+		priority = 1
+		criteria {
+			cvss_range {
+				from = 1
+				to = %d
+			}
+		}
+		actions {
+			block_download {
+				unscanned = true
+				active = true
+			}
+		}
+	}
+}
+`, name, description, ruleName, rangeTo)
+}
+
+func testAccXraySecurityPolicy_badSecurity(name, description, ruleName, allowedLicense string) string {
+	return fmt.Sprintf(`
+resource "xray_security_policy" "test" {
+	name = "%s"
+	description = "%s"
+	type = "security"
+	rules {
+		name = "%s"
+		priority = 1
+		criteria {
+			allow_unknown = true
+			allowed_licenses = ["%s"]
+		}
+		actions {
+			block_download {
+				unscanned = true
+				active = true
+			}
+		}
+	}
+}
+`, name, description, ruleName, allowedLicense)
+}
+
+const securityPolicyCVSS = `resource "xray_security_policy" "{{ .resource_name }}" {
+	name = "{{ .policy_name }}"
+	description = "{{ .policy_description }}"
+	type = "security"
+	rules {
+		name = "{{ .rule_name }}"
+		priority = 1
+		criteria {	
+			cvss_range {
+				from = {{ .cvss_from }}
+				to = {{ .cvss_to }}
+			}
+		}
+		actions {
+			block_release_bundle_distribution = {{ .block_release_bundle_distribution }}
+			fail_build = {{ .fail_build }}
+			notify_watch_recipients = {{ .notify_watch_recipients }}
+			notify_deployer = {{ .notify_deployer }}
+			create_ticket_enabled = {{ .create_ticket_enabled }}
+			build_failure_grace_period_in_days = {{ .grace_period_days }}
+			block_download {
+				unscanned = {{ .block_unscanned }}
+				active = {{ .block_active }}
+			}
+		}
+	}
+}`
+
+const securityPolicyMinSeverity = `resource "xray_security_policy" "{{ .resource_name }}" {
+	name = "{{ .policy_name }}"
+	description = "{{ .policy_description }}"
+	type = "security"
+	rules {
+		name = "{{ .rule_name }}"
+		priority = 1
+		criteria {
+            min_severity = "{{ .min_severity }}"
+		}
+		actions {
+			block_release_bundle_distribution = {{ .block_release_bundle_distribution }}
+			fail_build = {{ .fail_build }}
+			notify_watch_recipients = {{ .notify_watch_recipients }}
+			notify_deployer = {{ .notify_deployer }}
+			create_ticket_enabled = {{ .create_ticket_enabled }}
+			build_failure_grace_period_in_days = {{ .grace_period_days }}
+			block_download {
+				unscanned = {{ .block_unscanned }}
+				active = {{ .block_active }}
+			}
+		}
+	}
+}`
diff --git a/pkg/xray/resource_xray_watch_test.go b/pkg/xray/resource_xray_watch_test.go
deleted file mode 100644
index 49cb60a4..00000000
--- a/pkg/xray/resource_xray_watch_test.go
+++ /dev/null
@@ -1,330 +0,0 @@
-package xray
-
-import (
-	"fmt"
-	"github.com/go-resty/resty/v2"
-	"net/http"
-
-	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
-	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
-)
-
-// Test was temporarily removed from the test suite
-//func TestAccWatch_basic(t *testing.T) {
-//	watchName := "test-watch"
-//	policyName := "test-policy"
-//	watchDesc := "watch created by xray acceptance tests"
-//	resourceName := "xray_watch.test"
-//
-//	resource.Test(t, resource.TestCase{
-//		PreCheck:     func() { testAccPreCheck(t) },
-//		CheckDestroy: testAccCheckWatchDestroy,
-//		Providers:    testAccProviders,
-//		Steps: []resource.TestStep{
-//			{
-//				Config: testAccXrayWatchBasic(watchName, watchDesc, policyName),
-//				Check: resource.ComposeTestCheckFunc(
-//					resource.TestCheckResourceAttr(resourceName, "name", watchName),
-//					resource.TestCheckResourceAttr(resourceName, "description", watchDesc),
-//					resource.TestCheckResourceAttr(resourceName, "resources.0.type", "all-repos"),
-//					resource.TestCheckResourceAttr(resourceName, "assigned_policies.0.name", policyName),
-//					resource.TestCheckResourceAttr(resourceName, "assigned_policies.0.type", "security"),
-//				),
-//			},
-//			{
-//				ResourceName:      resourceName,
-//				ImportState:       true,
-//				ImportStateVerify: false,
-//			},
-//			{
-//				Config: testAccXrayWatchUnassigned(policyName),
-//				Check: resource.ComposeTestCheckFunc(
-//					testAccCheckWatchDoesntExist(resourceName),
-//				),
-//			},
-//		},
-//	})
-//}
-
-// These two tests are commented out because repoName and binMgrId must be real values but neither are terraformable so can't be put into these tests
-// I have tested this with some real values, but for obvious privacy reasons am not leaving those real values in here
-/*func TestAccWatch_filters(t *testing.T) {
-	watchName := "test-watch"
-	watchDesc := "watch created by xray acceptance tests"
-	repoName := "repo-name"
-	binMgrId := "artifactory-id"
-	policyName := fmt.Sprintf("test-policy%d",randomInt())
-	filterValue := "Debian"
-	updatedDesc := "updated watch description"
-	updatedValue := "Docker"
-	resourceName := "xray_watch.test"
-
-	resource.Test(t, resource.TestCase{
-		PreCheck:     func() { testAccPreCheck(t) },
-		CheckDestroy: testAccCheckWatchDestroy,
-		ProviderFactories: testAccProviders,
-		Steps: []resource.TestStep{
-			{
-				Config: testAccXrayWatchFilters(watchName, watchDesc, repoName, binMgrId, policyName, filterValue),
-				Check: resource.ComposeTestCheckFunc(
-					resource.TestCheckResourceAttr(resourceName, "name", watchName),
-					resource.TestCheckResourceAttr(resourceName, "description", watchDesc),
-					resource.TestCheckResourceAttr(resourceName, "resources.0.filters.0.type", "package-type"),
-					resource.TestCheckResourceAttr(resourceName, "resources.0.filters.0.value", filterValue),
-					resource.TestCheckResourceAttr(resourceName, "resources.0.type", "repository"),
-				),
-			},
-			{
-				ResourceName:      resourceName,
-				ImportState:       true,
-				ImportStateVerify: false,
-			},
-			{
-				Config: testAccXrayWatchFilters(watchName, updatedDesc, repoName, binMgrId, policyName, updatedValue),
-				Check: resource.ComposeTestCheckFunc(
-					resource.TestCheckResourceAttr(resourceName, "name", watchName),
-					resource.TestCheckResourceAttr(resourceName, "description", updatedDesc),
-					resource.TestCheckResourceAttr(resourceName, "resources.0.filters.0.type", "package-type"),
-					resource.TestCheckResourceAttr(resourceName, "resources.0.filters.0.value", updatedValue),
-					resource.TestCheckResourceAttr(resourceName, "resources.0.type", "repository"),
-				),
-			},
-			{
-				Config: testAccXrayWatchUnassigned(policyName),
-				Check: resource.ComposeTestCheckFunc(
-					testAccCheckWatchDoesntExist(resourceName),
-				),
-			},
-		},
-	})
-}
-
-func TestAccWatch_builds(t *testing.T) {
-	watchName := "test-watch"
-	policyName := "test-policy"
-	watchDesc := "watch created by xray acceptance tests"
-	binMgrId := "artifactory-id"
-	resourceName := "xray_watch.test"
-
-	resource.Test(t, resource.TestCase{
-		PreCheck:     func() { testAccPreCheck(t) },
-		CheckDestroy: testAccCheckWatchDestroy,
-		ProviderFactories: testAccProviders,
-		Steps: []resource.TestStep{
-			{
-				Config: testAccXrayWatchBuilds(watchName, watchDesc, policyName, binMgrId),
-				Check: resource.ComposeTestCheckFunc(
-					resource.TestCheckResourceAttr(resourceName, "name", watchName),
-					resource.TestCheckResourceAttr(resourceName, "description", watchDesc),
-					resource.TestCheckResourceAttr(resourceName, "resources.0.type", "all-builds"),
-					resource.TestCheckResourceAttr(resourceName, "assigned_policies.0.name", policyName),
-					resource.TestCheckResourceAttr(resourceName, "assigned_policies.0.type", "security"),
-				),
-			},
-			{
-				ResourceName:      resourceName,
-				ImportState:       true,
-				ImportStateVerify: false,
-			},
-			{
-				Config: testAccXrayWatchUnassigned(policyName),
-				Check: resource.ComposeTestCheckFunc(
-					testAccCheckWatchDoesntExist(resourceName),
-				),
-			},
-		},
-	})
-}*/
-
-func testAccCheckWatchDoesntExist(resourceName string) resource.TestCheckFunc {
-	return func(s *terraform.State) error {
-		_, ok := s.RootModule().Resources[resourceName]
-		if ok {
-			return fmt.Errorf("watch %s exists when it shouldn't", resourceName)
-		}
-		return nil
-	}
-}
-
-func testAccCheckWatchDestroy(s *terraform.State) error {
-	provider, _ := testAccProviders["artifactory"]()
-
-	client := provider.Meta().(*resty.Client)
-
-	for _, rs := range s.RootModule().Resources {
-		if rs.Type == "xray_watch" {
-			watch := Watch{}
-			resp, err := client.R().SetResult(&watch).Get("xray/api/v2/watches/" + rs.Primary.ID)
-			if err != nil {
-				if resp != nil && resp.StatusCode() == http.StatusNotFound {
-					continue
-				}
-				return err
-			}
-
-			return fmt.Errorf("error: Watch %s still exists %s", rs.Primary.ID, *watch.GeneralData.Name)
-
-		}
-		if rs.Type == "xray_policy" {
-			policy, resp, err := getPolicy(rs.Primary.ID, client)
-
-			if err != nil {
-				if resp != nil && resp.StatusCode() == http.StatusInternalServerError &&
-					err.Error() != fmt.Sprintf("{\"error\":\"Failed to find Policy %s\"}", rs.Primary.ID) {
-					continue
-				}
-				return err
-			}
-			return fmt.Errorf("error: Policy %s still exists %s", rs.Primary.ID, *policy.Name)
-		}
-	}
-
-	return nil
-}
-
-func testAccXrayWatchBasic(name, description, policyName string) string {
-	return fmt.Sprintf(`
-resource "xray_policy" "test" {
-	name  = "%s"
-	description = "test policy description"
-	type = "security"
-
-	rules {
-		name = "rule-name"
-		priority = 1
-		criteria {
-			min_severity = "High"
-		}
-		actions {
-			block_download {
-				unscanned = true
-				active = true
-			}
-		}
-	}
-}
-
-resource "xray_watch" "test" {
-	name  = "%s"
-	description = "%s"
-	resources {
-		type = "all-repos"
-		name = "All Repositories"
-	}
-	assigned_policies {
-		name = xray_policy.test.name
-		type = "security"
-	}
-	watch_recipients = ["test@example.com"]
-}
-`, policyName, name, description)
-}
-
-// Since policies can't be deleted if they have a watch assigned, we need to force terraform to delete the watch first
-// by removing it from the code at the end of every test step
-func testAccXrayWatchUnassigned(policyName string) string {
-	return fmt.Sprintf(`
-resource "xray_policy" "test" {
-	name  = "%s"
-	description = "test policy description"
-	type = "security"
-
-	rules {
-		name = "rule-name"
-		priority = 1
-		criteria {
-			min_severity = "High"
-		}
-		actions {
-			block_download {
-				unscanned = true
-				active = true
-			}
-		}
-	}
-}
-`, policyName)
-}
-
-// You seemingly can't do filters with all-repos - it's an example in the docs but doesn't seem possible via the web ui
-//func testAccXrayWatchFilters(name, description, repoName, binMgrId, policyName, filterValue string) string {
-//	return fmt.Sprintf(`
-//resource "xray_policy" "test" {
-//	name  = "%s"
-//	description = "test policy description"
-//	type = "security"
-//
-//	rules {
-//		name = "rule-name"
-//		priority = 1
-//		criteria {
-//			min_severity = "High"
-//		}
-//		actions {
-//			block_download {
-//				unscanned = true
-//				active = true
-//			}
-//		}
-//	}
-//}
-//
-//resource "xray_watch" "test" {
-//	name  = "%s"
-//	description = "%s"
-//	resources {
-//		type = "repository"
-//		name = "%s"
-//		bin_mgr_id = "%s"
-//		filters {
-//			type = "package-type"
-//			value = "%s"
-//		}
-//	}
-//	assigned_policies {
-//		name = xray_policy.test.name
-//		type = "security"
-//	}
-//}
-//`, policyName, name, description, repoName, binMgrId, filterValue)
-//}
-//
-//func testAccXrayWatchBuilds(name, description, policyName, binMgrId string) string {
-//	return fmt.Sprintf(`
-//resource "xray_policy" "test" {
-//	name  = "%s"
-//	description = "test policy description"
-//	type = "security"
-//
-//	rules {
-//		name = "rule-name"
-//		priority = 1
-//		criteria {
-//			min_severity = "High"
-//		}
-//		actions {
-//			block_download {
-//				unscanned = true
-//				active = true
-//			}
-//		}
-//	}
-//}
-//
-//resource "xray_watch" "test" {
-//	name = "%s"
-//	description = "%s"
-//	resources {
-//		type = "all-builds"
-//		name = "All Builds"
-//		bin_mgr_id = "%s"
-//	}
-//	assigned_policies {
-//		name = xray_policy.test.name
-//		type = "security"
-//	}
-//}
-//`, policyName, name, description, binMgrId)
-//}
-
-// TODO for bonus points - test builds with complex filters eg "filters":[{"type":"ant-patterns","value":{"ExcludePatterns":[],"IncludePatterns":["*"]}