diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 86578ab0..13d71ece 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,8 +18,7 @@ jobs: goreleaser: runs-on: ubuntu-latest if: | - (startsWith(github.ref, 'refs/tags/') && github.event.base_ref == 'refs/heads/master') - || (startsWith(github.ref, 'refs/tags/') && github.event.base_ref == 'refs/heads/v6') + (startsWith(github.ref, 'refs/tags/') && github.event.base_ref == 'refs/heads/master') steps: - name: Checkout diff --git a/.gitignore b/.gitignore index 1a2433ff..5d066d75 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ terraform-provider-* dist/ vendor/ +bin/ .idea/ .github/ .modules/ @@ -13,5 +14,7 @@ lib/ /resources/ coverage.txt .scannerwork - +tfc-testing/.terraform +tfc-testing/terraform.d +tfc-testing/.terraform.lock.hcl .DS_Store diff --git a/.goreleaser.yml b/.goreleaser.yml index e8e2d3b0..7bcdf7d1 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -14,7 +14,7 @@ builds: flags: - -trimpath ldflags: - - '-s -w -X github.com/jfrog/terraform-provider-project/pkg/project.Version={{.Version}}' + - '-s -w -X github.com/jfrog/terraform-provider-project/pkg/project/provider.Version={{.Version}}' goos: - freebsd - windows diff --git a/CHANGELOG.md b/CHANGELOG.md index 4998b993..b3f5f491 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.6.0 (May 22, 2024) + +FEATURES: + +* provider: Add support for Terraform Cloud Workload Identity Token. PR: [#124](https://github.com/jfrog/terraform-provider-project/pull/124) + ## 1.5.3 (May 13, 2024) IMPROVEMENTS: diff --git a/GNUmakefile b/GNUmakefile index 8c0abf19..f06294be 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -26,8 +26,21 @@ install: clean build sed -i.bak '0,/version = ".*"/s//version = "${NEXT_VERSION}"/' sample.tf && rm sample.tf.bak && \ terraform init +install_tfc: clean build_tfc + mkdir -p tfc-testing/${BUILD_PATH} && \ + mkdir -p tfc-testing/terraform.d/plugins/registry.terraform.io/jfrog/${PRODUCT}/${NEXT_VERSION}/linux_amd64 && \ + mv -v dist/terraform-provider-${PRODUCT}_${GORELEASER_ARCH}/terraform-provider-${PRODUCT}_v${NEXT_VERSION}* tfc-testing/${BUILD_PATH} && \ + mv -v dist/terraform-provider-${PRODUCT}_linux_amd64_v1/terraform-provider-${PRODUCT}_v${NEXT_VERSION}* tfc-testing/terraform.d/plugins/registry.terraform.io/jfrog/${PRODUCT}/${NEXT_VERSION}/linux_amd64 && \ + sed -i.bak '0,/version = ".*"/s//version = "${NEXT_VERSION}"/' tfc-testing/sample.tf && rm tfc-testing/sample.tf.bak && \ + cd tfc-testing && \ + terraform providers lock -platform=linux_amd64 -platform=darwin_amd64 -fs-mirror=terraform.d/plugins && \ + terraform init + clean: - rm -fR dist terraform.d/ .terraform terraform.tfstate* terraform.d/ .terraform.lock.hcl + rm -fR dist terraform.d/ .terraform terraform.tfstate* .terraform.lock.hcl + +clean_tfc: + rm -fR dist tfc-testing/terraform.d/ tfc-testing/.terraform tfc-testing/terraform.tfstate* tfc-testing/.terraform.lock.hcl release: @git tag ${NEXT_VERSION} && git push --mirror @@ -41,16 +54,23 @@ update_pkg_cache: build: fmt GORELEASER_CURRENT_TAG=${NEXT_VERSION} goreleaser build --single-target --clean --snapshot +build_tfc: fmt + GORELEASER_CURRENT_TAG=${NEXT_VERSION} goreleaser build --clean --snapshot --config tfc-testing/.goreleaser.yml + test: @echo "==> Starting unit tests" go test $(TEST) -timeout=30s -parallel=4 +test_tfc: install_tfc + cd tfc-testing && \ + terraform plan + attach: dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient attach $$(pgrep terraform-provider-${PRODUCT}) acceptance: fmt export TF_ACC=true && \ - go test -cover -coverprofile=coverage.txt -ldflags="-X '${PKG_VERSION_PATH}.Version=${NEXT_VERSION}-test'" -v -p 1 -parallel 20 -timeout 20m ./pkg/... + go test -cover -coverprofile=coverage.txt -ldflags="-X '${PKG_VERSION_PATH}/provider.Version=${NEXT_VERSION}-test'" -v -p 1 -parallel 20 -timeout 20m ./pkg/... # To generate coverage.txt run `make acceptance` first coverage: diff --git a/docs/index.md b/docs/index.md index e65978a3..0f27e950 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,5 +1,4 @@ --- -layout: "" page_title: "Artifactory Project Provider" description: |- The Artifactory Project provider provides resources to interact with project supported by Artifactory. @@ -24,11 +23,6 @@ curl -sL ${host}/projects/api/system/licenses/ | jq . } ``` -The following 3 license types (`jq .type`) do **NOT** support APIs: -- Community Edition for C/C++ -- JCR Edition -- OSS - ## Example Usage ```terraform @@ -184,7 +178,9 @@ resource "project_environment" "myenv" { ## Authentication -The Artifactory Project provider supports one type of authentication using Bearer token. +The Artifactory provider supports two ways of authentication. The following methods are supported: +* Bearer Token +* Terraform Cloud OIDC provider ### Bearer Token @@ -199,11 +195,67 @@ provider "project" { } ``` +### Terraform Cloud OIDC Provider + +If you are using this provider on Terraform Cloud and wish to use dynamic credentials instead of static access token for authentication with JFrog platform, you can leverage Terraform as the OIDC provider. + +To setup dynamic credentials, follow these steps: +1. Configure Terraform Cloud as a generic OIDC provider +2. Set environment variable in your Terraform Workspace +3. Setup Terraform Cloud in your configuration + +During the provider start up, if it finds env var `TFC_WORKLOAD_IDENTITY_TOKEN` it will use this token with your JFrog instance to exchange for a short-live access token. If that is successful, the provider will the access token for all subsequent API requests with the JFrog instance. + +#### Configure Terraform Cloud as generic OIDC provider + +Follow [confgure an OIDC integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-an-oidc-integration). Enter a name for the provider, e.g. `terraform-cloud`. Use `https://app.terraform.io` for "Provider URL". Choose your own value for "Audience", e.g. `jfrog-terraform-cloud`. + +Then [configure an identity mapping](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-identity-mappings) with an empty "Claims JSON" (`{}`), and select the "Token scope", "User", and "Service" as desired. + +#### Set environment variable in your Terraform Workspace + +In your workspace, add an environment variable `TFC_WORKLOAD_IDENTITY_AUDIENCE` with audience value (e.g. `jfrog-terraform-cloud`) from JFrog OIDC integration above. See [Manually Generating Workload Identity Tokens](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/manual-generation) for more details. + +When a run starts on Terraform Cloud, it will create a workload identity token with the specified audience and assigns it to the environment variable `TFC_WORKLOAD_IDENTITY_TOKEN` for the provider to consume. + +#### Setup Terraform Cloud in your configuration + +Add `cloud` block to `terraform` block, and add `oidc_provider_name` attribute (from JFrog OIDC integration) to provider block: + +```terraform +terraform { + cloud { + organization = "my-org" + workspaces { + name = "my-workspace" + } + } + + required_providers { + project = { + source = "jfrog/project" + version = "1.6.0" + } + } +} + +provider "project" { + url = "https://myinstance.jfrog.io" + oidc_provider_name = "terraform-cloud" +} +``` + +**Note:** Ensure `access_token` attribute and `JFROG_ACCESS_TOKEN` env var are not set + ## Schema +### Required + +- `url` (String) URL of Artifactory. This can also be sourced from the `PROJECT_URL` or `JFROG_URL` environment variable. Default to 'http://localhost:8081' if not set. + ### Optional - `access_token` (String, Sensitive) This is a Bearer token that can be given to you by your admin under `Identity and Access`. This can also be sourced from the `PROJECT_ACCESS_TOKEN` or `JFROG_ACCESS_TOKEN` environment variable. Defauult to empty string if not set. - `check_license` (Boolean) Toggle for pre-flight checking of Artifactory Enterprise license. Default to `true`. -- `url` (String) URL of Artifactory. This can also be sourced from the `PROJECT_URL` or `JFROG_URL` environment variable. Default to 'http://localhost:8081' if not set. +- `oidc_provider_name` (String) OIDC provider name. See [Configure an OIDC Integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-an-oidc-integration) for more details. diff --git a/http/http-client.env.json b/http/http-client.env.json deleted file mode 100644 index ee252265..00000000 --- a/http/http-client.env.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "localhost" : { - "host" : "http://localhost:8081", - "prjKey" : "christ", - "user" : "cbongiorno" - }, - "partnership": { - "host" : "https://partnership.jfrog.io" - } -} diff --git a/http/projects.http b/http/projects.http deleted file mode 100644 index 93f407a3..00000000 --- a/http/projects.http +++ /dev/null @@ -1,94 +0,0 @@ -GET {{ host }}/access/api/v1/projects -Accept: application/json -Content-Type: application/json -Authorization: Bearer {{ token }} -### - - - -POST {{ host }}/access/api/v1/projects -Accept: application/json -Content-Type: application/json -Authorization: Bearer {{ token }} - -{ - "display_name": "prj-{{ $uuid }}", - "description": "a test project", - "admin_privileges": { - "manage_members": true, - "manage_resources": true, - "manage_security_assets": true, - "index_resources": true, - "allow_ignore_rules": true - }, - "storage_quota_bytes": -1, - "project_key": "{{prjKey}}" -} - -### -GET {{ host }}/access/api/v1/projects/{{prjKey}}/ -Accept: application/json -Content-Type: application/json -Authorization: Bearer {{ token }} - -### -GET {{ host }}/access/api/v1/projects/{{prjKey}}/users/ -Accept: application/json -Content-Type: application/json -Authorization: Bearer {{ token }} - -### -GET {{ host }}/access/api/v1/projects/{{prjKey}}/roles/ -Accept: application/json -Content-Type: application/json -Authorization: Bearer {{ token }} -### - -GET {{ host }}/access/api/v1/projects/{{prjKey}}/roles/Project%20Admin -Accept: application/json -Content-Type: application/json -Authorization: Bearer {{ token }} -### - -GET {{ host }}/access/api/v1/projects/{{prjKey}}/users/{{user}} -Accept: application/json -Content-Type: application/json -Authorization: Bearer {{ token }} - -### the role is case sensitive and the user won't show up if it's wrong and you won't get rejected -PUT {{ host }}/access/api/v1/projects/{{prjKey}}/users/{{user}} -Accept: application/json -Content-Type: application/json -Authorization: Bearer {{ token }} - -{ - "roles": [ - "Developer", - "Project Admin" - ] -} -### there is no way to determine which repositories are in a project -## even the UI doesn't work -GET {{ host }}/artifactory/api/repositories/?prjKey={{prjKey}} -Accept: application/json -Content-Type: application/json -Authorization: Bearer {{ token }} -### - -GET {{ host }}/ui/api/v1/projects/{{prjKey}}/ -Accept: application/json -Content-Type: application/json -Authorization: Bearer {{ token }} - -### the group 'writeAccess' exists in the UI but not here -GET {{ host }}/access/api/v1/projects/{{prjKey}}/groups/ -Accept: application/json -Content-Type: application/json -Authorization: Bearer {{ token }} - -### the group 'writeAccess' exists in the UI but not here -GET {{ host }}/access/api/v1/projects/{{prjKey}}/groups/readers -Accept: application/json -Content-Type: application/json -Authorization: Bearer {{ token }} - diff --git a/pkg/project/provider/framework.go b/pkg/project/provider/framework.go index cc7d0ad9..66b4e2ec 100644 --- a/pkg/project/provider/framework.go +++ b/pkg/project/provider/framework.go @@ -24,9 +24,10 @@ type ProjectProvider struct{} // ProjectProviderModel describes the provider data model. type ProjectProviderModel struct { - Url types.String `tfsdk:"url"` - AccessToken types.String `tfsdk:"access_token"` - CheckLicense types.Bool `tfsdk:"check_license"` + Url types.String `tfsdk:"url"` + AccessToken types.String `tfsdk:"access_token"` + OIDCProviderName types.String `tfsdk:"oidc_provider_name"` + CheckLicense types.Bool `tfsdk:"check_license"` } // Metadata satisfies the provider.Provider interface for ProjectProvider @@ -54,6 +55,13 @@ func (p *ProjectProvider) Schema(ctx context.Context, req provider.SchemaRequest }, Description: "This is a Bearer token that can be given to you by your admin under `Identity and Access`. This can also be sourced from the `PROJECT_ACCESS_TOKEN` or `JFROG_ACCESS_TOKEN` environment variable. Defauult to empty string if not set.", }, + "oidc_provider_name": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + }, + Description: "OIDC provider name. See [Configure an OIDC Integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-an-oidc-integration) for more details.", + }, "check_license": schema.BoolAttribute{ Optional: true, Description: "Toggle for pre-flight checking of Artifactory Enterprise license. Default to `true`.", @@ -98,8 +106,23 @@ func (p *ProjectProvider) Configure(ctx context.Context, req provider.ConfigureR return } - // Check configuration data, which should take precedence over + oidcAccessToken, err := util.OIDCTokenExchange(ctx, restyClient, config.OIDCProviderName.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "Failed OIDC ID token exchange", + err.Error(), + ) + return + } + + // use token from OIDC provider, which should take precedence over // environment variable data, if found. + if oidcAccessToken != "" { + accessToken = oidcAccessToken + } + + // Check configuration data, which should take precedence over + // environment variable data or OIDC access token, if found. if config.AccessToken.ValueString() != "" { accessToken = config.AccessToken.ValueString() } diff --git a/pkg/project/provider/sdkv2.go b/pkg/project/provider/sdkv2.go index 65d6e7ef..ef8f3d51 100644 --- a/pkg/project/provider/sdkv2.go +++ b/pkg/project/provider/sdkv2.go @@ -11,6 +11,7 @@ import ( "github.com/jfrog/terraform-provider-shared/client" "github.com/jfrog/terraform-provider-shared/util" "github.com/jfrog/terraform-provider-shared/util/sdk" + "github.com/jfrog/terraform-provider-shared/validator" ) // Provider Projects provider that supports configuration via a token @@ -20,18 +21,21 @@ func SdkV2() *schema.Provider { Schema: map[string]*schema.Schema{ "url": { Type: schema.TypeString, - Required: true, - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"PROJECT_URL", "JFROG_URL"}, "http://localhost:8081"), + Optional: true, ValidateFunc: validation.IsURLWithHTTPorHTTPS, Description: "URL of Artifactory. This can also be sourced from the `PROJECT_URL` or `JFROG_URL` environment variable. Default to 'http://localhost:8081' if not set.", }, "access_token": { + Type: schema.TypeString, + Optional: true, + Sensitive: true, + Description: "This is a Bearer token that can be given to you by your admin under `Identity and Access`. This can also be sourced from the `PROJECT_ACCESS_TOKEN` or `JFROG_ACCESS_TOKEN` environment variable. Defauult to empty string if not set.", + }, + "oidc_provider_name": { Type: schema.TypeString, - Required: true, - Sensitive: true, - DefaultFunc: schema.MultiEnvDefaultFunc([]string{"PROJECT_ACCESS_TOKEN", "JFROG_ACCESS_TOKEN"}, ""), - ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotEmpty), - Description: "This is a Bearer token that can be given to you by your admin under `Identity and Access`. This can also be sourced from the `PROJECT_ACCESS_TOKEN` or `JFROG_ACCESS_TOKEN` environment variable. Defauult to empty string if not set.", + Optional: true, + ValidateDiagFunc: validator.StringIsNotEmpty, + Description: "OIDC provider name. See [Configure an OIDC Integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-an-oidc-integration) for more details.", }, "check_license": { Type: schema.TypeBool, @@ -61,40 +65,66 @@ func SdkV2() *schema.Provider { } func providerConfigure(ctx context.Context, d *schema.ResourceData, terraformVersion string) (interface{}, diag.Diagnostics) { - URL, ok := d.GetOk("url") - if URL == nil || URL == "" || !ok { - return nil, diag.Errorf("you must supply a URL") + url := util.CheckEnvVars([]string{"JFROG_URL", "PROJECT_URL"}, "") + accessToken := util.CheckEnvVars([]string{"JFROG_ACCESS_TOKEN", "PROJECT_ACCESS_TOKEN"}, "") + + if v, ok := d.GetOk("url"); ok { + url = v.(string) + } + if url == "" { + return nil, diag.Errorf("missing URL Configuration") } - restyBase, err := client.Build(URL.(string), productId) + restyClient, err := client.Build(url, productId) if err != nil { return nil, diag.FromErr(err) } - accessToken := d.Get("access_token").(string) - restyBase, err = client.AddAuth(restyBase, "", accessToken) + if v, ok := d.GetOk("oidc_provider_name"); ok { + oidcAccessToken, err := util.OIDCTokenExchange(ctx, restyClient, v.(string)) + if err != nil { + return nil, diag.FromErr(err) + } + + if oidcAccessToken != "" { + accessToken = oidcAccessToken + } + } + + if v, ok := d.GetOk("access_token"); ok && v != "" { + accessToken = v.(string) + } + + if accessToken == "" { + return nil, diag.Errorf("Missing JFrog Access Token\n" + + "While configuring the provider, the Access Token was not found in " + + "the JFROG_ACCESS_TOKEN/PROJECT_ACCESS_TOKEN environment variable or provider " + + "configuration block access_token attribute.") + } + + restyClient, err = client.AddAuth(restyClient, "", accessToken) if err != nil { return nil, diag.FromErr(err) } checkLicense := d.Get("check_license").(bool) if checkLicense { - licenseErr := util.CheckArtifactoryLicense(restyBase, "Enterprise", "Commercial", "Edge") + licenseErr := util.CheckArtifactoryLicense(restyClient, "Enterprise", "Commercial", "Edge") if licenseErr != nil { return nil, diag.FromErr(licenseErr) } } - version, err := util.GetArtifactoryVersion(restyBase) + version, err := util.GetArtifactoryVersion(restyClient) if err != nil { return nil, diag.FromErr(err) } featureUsage := fmt.Sprintf("Terraform/%s", terraformVersion) - util.SendUsage(ctx, restyBase.R(), productId, featureUsage) + go util.SendUsage(ctx, restyClient.R(), productId, featureUsage) return util.ProviderMetadata{ - Client: restyBase, + Client: restyClient, ArtifactoryVersion: version, }, nil } diff --git a/sample.tf b/sample.tf index e2d68ffc..d77dd6a0 100644 --- a/sample.tf +++ b/sample.tf @@ -2,7 +2,7 @@ terraform { required_providers { project = { source = "jfrog/project" - version = "1.5.1" + version = "1.5.3" } } } diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl index b1205d2d..c560f4bc 100644 --- a/templates/index.md.tmpl +++ b/templates/index.md.tmpl @@ -1,5 +1,4 @@ --- -layout: "" page_title: "Artifactory Project Provider" description: |- The Artifactory Project provider provides resources to interact with project supported by Artifactory. @@ -24,18 +23,15 @@ curl -sL ${host}/projects/api/system/licenses/ | jq . } ``` -The following 3 license types (`jq .type`) do **NOT** support APIs: -- Community Edition for C/C++ -- JCR Edition -- OSS - ## Example Usage {{tffile "examples/full.tf"}} ## Authentication -The Artifactory Project provider supports one type of authentication using Bearer token. +The Artifactory provider supports two ways of authentication. The following methods are supported: +* Bearer Token +* Terraform Cloud OIDC provider ### Bearer Token @@ -50,4 +46,56 @@ provider "project" { } ``` +### Terraform Cloud OIDC Provider + +If you are using this provider on Terraform Cloud and wish to use dynamic credentials instead of static access token for authentication with JFrog platform, you can leverage Terraform as the OIDC provider. + +To setup dynamic credentials, follow these steps: +1. Configure Terraform Cloud as a generic OIDC provider +2. Set environment variable in your Terraform Workspace +3. Setup Terraform Cloud in your configuration + +During the provider start up, if it finds env var `TFC_WORKLOAD_IDENTITY_TOKEN` it will use this token with your JFrog instance to exchange for a short-live access token. If that is successful, the provider will the access token for all subsequent API requests with the JFrog instance. + +#### Configure Terraform Cloud as generic OIDC provider + +Follow [confgure an OIDC integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-an-oidc-integration). Enter a name for the provider, e.g. `terraform-cloud`. Use `https://app.terraform.io` for "Provider URL". Choose your own value for "Audience", e.g. `jfrog-terraform-cloud`. + +Then [configure an identity mapping](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-identity-mappings) with an empty "Claims JSON" (`{}`), and select the "Token scope", "User", and "Service" as desired. + +#### Set environment variable in your Terraform Workspace + +In your workspace, add an environment variable `TFC_WORKLOAD_IDENTITY_AUDIENCE` with audience value (e.g. `jfrog-terraform-cloud`) from JFrog OIDC integration above. See [Manually Generating Workload Identity Tokens](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/manual-generation) for more details. + +When a run starts on Terraform Cloud, it will create a workload identity token with the specified audience and assigns it to the environment variable `TFC_WORKLOAD_IDENTITY_TOKEN` for the provider to consume. + +#### Setup Terraform Cloud in your configuration + +Add `cloud` block to `terraform` block, and add `oidc_provider_name` attribute (from JFrog OIDC integration) to provider block: + +```terraform +terraform { + cloud { + organization = "my-org" + workspaces { + name = "my-workspace" + } + } + + required_providers { + project = { + source = "jfrog/project" + version = "1.6.0" + } + } +} + +provider "project" { + url = "https://myinstance.jfrog.io" + oidc_provider_name = "terraform-cloud" +} +``` + +**Note:** Ensure `access_token` attribute and `JFROG_ACCESS_TOKEN` env var are not set + {{ .SchemaMarkdown | trimspace }} diff --git a/tfc-testing/.goreleaser.yml b/tfc-testing/.goreleaser.yml new file mode 100644 index 00000000..bf857d3d --- /dev/null +++ b/tfc-testing/.goreleaser.yml @@ -0,0 +1,27 @@ +# Visit https://goreleaser.com for documentation on how to customize this +# behavior. +before: + hooks: + # this is just an example and not a requirement for provider building/publishing + - go mod tidy +builds: +- env: + # goreleaser does not work with CGO, it could also complicate + # usage by users in CI/CD systems like Terraform Cloud where + # they are unable to install libraries. + - CGO_ENABLED=0 + mod_timestamp: '{{ .CommitTimestamp }}' + flags: + - -trimpath + ldflags: + - '-s -w -X github.com/jfrog/terraform-provider-project/pkg/project/provider.Version={{.Version}}' + goos: + - linux + - darwin + goarch: + - amd64 + ignore: + - goos: darwin + goarch: '386' + binary: '{{ .ProjectName }}_v{{ .Version }}' + diff --git a/tfc-testing/sample.tf b/tfc-testing/sample.tf new file mode 100644 index 00000000..4e4eff15 --- /dev/null +++ b/tfc-testing/sample.tf @@ -0,0 +1,34 @@ +terraform { + cloud { + organization = "jfrog-partnership-engineering" + workspaces { + name = "alexh" + } + } + + required_providers { + project = { + source = "jfrog/project" + version = "1.5.3" + } + } +} + +provider "project" { + url = "https://partnership.jfrog.io" + oidc_provider_name = "terraform-cloud" +} + +resource "project" "myproject" { + key = "myproj" + display_name = "My Project" + description = "My Project" + admin_privileges { + manage_members = true + manage_resources = true + index_resources = true + } + max_storage_in_gibibytes = 10 + block_deployments_on_limit = false + email_notification = true +}