diff --git a/.changes/unreleased/ENHANCEMENTS-20260724-172011.yaml b/.changes/unreleased/ENHANCEMENTS-20260724-172011.yaml new file mode 100644 index 0000000..04aaa00 --- /dev/null +++ b/.changes/unreleased/ENHANCEMENTS-20260724-172011.yaml @@ -0,0 +1,3 @@ +kind: ENHANCEMENTS +body: Running tfctl, tfctl version, or tfctl --version checks whether there is a newer version of tfctl available and whether `auth login` needs to be run. +time: 2026-07-24T17:20:11.173085-06:00 diff --git a/.changes/unreleased/ENHANCEMENTS-20260728-150652.yaml b/.changes/unreleased/ENHANCEMENTS-20260728-150652.yaml new file mode 100644 index 0000000..5589259 --- /dev/null +++ b/.changes/unreleased/ENHANCEMENTS-20260728-150652.yaml @@ -0,0 +1,3 @@ +kind: ENHANCEMENTS +body: tfctl now detects outdated skills it installed and migrates them to the latest version. +time: 2026-07-28T15:06:52.901832-06:00 diff --git a/.changes/v0.4.0-beta.md b/.changes/v0.4.0-beta.md index 24061af..32dd5a8 100644 --- a/.changes/v0.4.0-beta.md +++ b/.changes/v0.4.0-beta.md @@ -3,7 +3,7 @@ NEW FEATURES: -* Adds the `harness exec` command, which lets a human grant session-scoped, noninteractive `tfctl` delete permissions to a wrapped command (such as a coding agent) via `--allow-delete`. The grant is tied to the wrapped process, auto-reverts when it exits, and never covers the irreversible `organizations` and `projects` classes unless they are named explicitly. +* Adds the `harness exec` command, which lets a human grant session-scoped, noninteractive `tfctl` delete permissions to a wrapped command (such as a coding agent) via `--allow-delete`. The grant is tied to all subprocesses. ENHANCEMENTS: diff --git a/CHANGELOG.md b/CHANGELOG.md index ac2b61b..8fec2c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ NEW FEATURES: -* Adds the `harness exec` command, which lets a human grant session-scoped, noninteractive `tfctl` delete permissions to a wrapped command (such as a coding agent) via `--allow-delete`. The grant is tied to the wrapped process, auto-reverts when it exits, and never covers the irreversible `organizations` and `projects` classes unless they are named explicitly. +* Adds the `harness exec` command, which lets a human grant session-scoped, noninteractive `tfctl` delete permissions to a wrapped command (such as a coding agent) via `--allow-delete`. The grant is tied to all subprocesses. ENHANCEMENTS: diff --git a/Makefile b/Makefile index 78f975c..a174657 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,9 @@ SHELL=/usr/bin/env bash NAME=tfctl BIN_PATH ?= dist/$(NAME) ASSETS ?= assets +VERSION_FILE ?= version/VERSION +SKILL_HASHES = skills/tfctl/known_release_hashes +SKILL_EMBEDDED = skills/tfctl/SKILL.md ifeq ($(GOARCH), arm64) GOARCH = arm64 @@ -40,6 +43,11 @@ gen/screenshot: go/install # Create a screenshot of the tfctl CLI gen/logo: logotools @lolcat -S 26 -f <(figlet -d ./assets -f "Sub-Zero.flf" tfctl) > ./cmd/tfctl/logo.txt +.PHONY: gen/openapi +gen/openapi: + @curl -s -o ./internal/pkg/openapi/spec/hcpt_v2_public_beta.json https://app.terraform.io/openapi/prerelease.json + @echo "Embedded OpenAPI spec updated successfully" + .PHONY: go/build go/build: bin @@ -65,6 +73,15 @@ go/fmt: fmt-check: @test -z "$$(gofmt -s -l . | tee /dev/stderr)" || (echo "Code is not formatted. Run 'make go/fmt'" && exit 1) +# Release targets +.PHONY: prepare-release +prepare-release: gen/openapi + @if [ -z "$(VERSION)" ]; then echo "VERSION is not set"; exit 1; fi + @echo $(VERSION) > $(VERSION_FILE) + @echo "Updated $(VERSION_FILE) to $(VERSION)" + @echo "$$(shasum -a 256 $(SKILL_EMBEDDED) | cut -d' ' -f1) v$(VERSION)" >> $(SKILL_HASHES) + @echo "Appended sha256 for $(SKILL_EMBEDDED) to $(SKILL_HASHES)" + # Install development tools .PHONY: tools tools: @@ -97,20 +114,25 @@ help: @echo "Available targets:" @echo "" @echo "Tools:" - @echo " tools Install development tools" - @echo " gen/screenshot Generate a screenshot of the CLI in $(ASSETS)/" - @echo " gen/logo Generate the ASCII art logo" + @echo " tools Install development tools" + @echo " gen/screenshot Generate a screenshot of the CLI in $(ASSETS)/" + @echo " gen/logo Generate the ASCII art logo" @echo "" @echo "Build:" - @echo " go/install Install tfctl binary to GOPATH/bin" - @echo " bin Build a binary for tfctl ($(BIN_PATH))" - @echo " clean Clean build artifacts" - @echo " docker Build a docker image for tfctl" + @echo " go/install Install tfctl binary to GOPATH/bin" + @echo " bin Build a binary for tfctl ($(BIN_PATH))" + @echo " clean Clean build artifacts" + @echo " docker Build a docker image for tfctl" @echo "" @echo "Code:" - @echo " check Run all checks (formatting, linting, tests)" - @echo " go/test Run all tests" - @echo " go/lint Run golangci-lint" - @echo " go/fmt Format go code" - @echo " fmt-check Check go code formatting" + @echo " check Run all checks (formatting, linting, tests)" + @echo " go/test Run all tests" + @echo " go/lint Run golangci-lint" + @echo " go/fmt Format go code" + @echo " fmt-check Check go code formatting" + @echo "" + @echo "Release:" + @echo " gen/openapi Update embedded OpenAPI spec" + @echo " prepare-release Prepare next semantic version release," + @echo " requires VERSION argument" @echo "" \ No newline at end of file diff --git a/README.md b/README.md index 7ed446b..e516656 100644 --- a/README.md +++ b/README.md @@ -165,9 +165,9 @@ The CLI stores configuration for individual profiles in the `profiles` subdirect If you have not configured a token for the active profile with `tfctl auth login`, the `tfctl` CLI checks your Terraform configuration for a matching token. These tokens may either be in your Terraform configuration directory, for example `~/.terraform.d/credentials.tfrc.json`, or the corresponding Terraform environment variables, such as `TF_TOKEN_app_terraform_io`. -### Environment variables +### Profile Environment variables -If you have not configured a particular option for the active profile, `tfctl` checks the following environment variables: +If you have **not** configured a particular option for the active profile, `tfctl` checks the following environment variables: `TFCTL_ORGANIZATION`: The organization to use for commands that require an organization. @@ -179,6 +179,14 @@ If you have not configured a particular option for the active profile, `tfctl` c `TF_TOKEN_`: An HCP Terraform API token to present during authentication, with the specified hostname in Punycode formatting, for example `TF_TOKEN_app_terraform_io`. The CLI present the Terraform token only if it has not been configured in any other way. +### Behavior Environment Variables + +`TFCTL_CONFIG_DIR`: Change the location of the tfctl config directory, which is `~/.config/tfctl` by default. + +`TFCTL_SKIP_MIGRATE`: Don't migrate installed skill files to the latest version (if contents are known to be installed by a previous version). + +`CHECKPOINT_DISABLE`: Don't check for newer versions of tfctl. + ## Command reference ![tfctl](assets/tfctl.png "tfctl") diff --git a/cmd/tfctl/main.go b/cmd/tfctl/main.go index 1bf0e97..6f0feca 100644 --- a/cmd/tfctl/main.go +++ b/cmd/tfctl/main.go @@ -6,7 +6,6 @@ package main import ( "context" - _ "embed" "errors" "fmt" "os" @@ -22,21 +21,60 @@ import ( "github.com/hashicorp/tfctl-cli/internal/pkg/checkpoint" "github.com/hashicorp/tfctl-cli/internal/pkg/cmd" "github.com/hashicorp/tfctl-cli/internal/pkg/format" - "github.com/hashicorp/tfctl-cli/internal/pkg/heredoc" "github.com/hashicorp/tfctl-cli/internal/pkg/iostreams" "github.com/hashicorp/tfctl-cli/internal/pkg/logging" "github.com/hashicorp/tfctl-cli/internal/pkg/profile" "github.com/hashicorp/tfctl-cli/internal/pkg/telemetry" + "github.com/hashicorp/tfctl-cli/skills" "github.com/hashicorp/tfctl-cli/version" ) -//go:embed logo.txt -var Logo string +var ( + envSkipMigrate = "TFCTL_SKIP_MIGRATE" + envCheckpointDisable = "CHECKPOINT_DISABLE" +) func main() { os.Exit(realMain()) } +func isGlobalBooleanArg(arg string, bareForm string) bool { + return arg == bareForm || arg == fmt.Sprintf("%s=true", bareForm) +} + +func isDryRun(args []string) bool { + for _, a := range args { + if isGlobalBooleanArg(a, "--dry-run") { + return true + } + } + return false +} + +func isVersion(args []string) bool { + if len(args) == 0 { + return true + } + + allowVersionCommand := true + for _, arg := range args { + if !strings.HasPrefix(arg, "-") { + // A non-flag argument before version flags indicates that this is not a version request. + return false + } + + if !isGlobalBooleanArg(arg, "--no-color") && !isGlobalBooleanArg(arg, "--debug") && !isGlobalBooleanArg(arg, "--quiet") { + allowVersionCommand = false + } + + // Any of these coming first indicate a version command + if arg == "-v" || arg == "-version" || arg == "--version" { + return true + } + } + return allowVersionCommand +} + func realMain() int { args := os.Args[1:] @@ -65,29 +103,36 @@ func realMain() int { // Explore relevant global args before the command parses them to set up non-command output initialLogLevel := logging.LevelDefault for _, a := range args { - if a == "--debug" { + if isGlobalBooleanArg(a, "--debug") { initialLogLevel = logging.LevelDebug } - if a == "--no-color" { + if isGlobalBooleanArg(a, "--no-color") { io.ForceNoColor() } - if a == "--quiet" { + if isGlobalBooleanArg(a, "--quiet") { io.SetQuiet(true) } } - // The logger level will need to be set by the command after parsing flags. + // The actual logger level will be set by the command after parsing flags. logger := logging.NewLogger(io, initialLogLevel) - // Add the logger to the shutdown context because this is the context used throughout - // the command execution lifecycle. + // Add the logger to the main context for use everywhere else. shutdownCtx = logging.WithLogger(shutdownCtx, logger) - // Run the checkpoint request in a separate goroutine. It's important to always execute + // Checkpoint is HashiCorp's service for checking the current version against the + // latest, providing any relevant warnings about the current release in rare situations. + // Run the request in a separate goroutine. It's important to always execute // this without condition because checkForNewVersion will block until it is complete - go checkpoint.Run(shutdownCtx, os.Getenv("CHECKPOINT_DISABLE") != "") + go checkpoint.Run(shutdownCtx, os.Getenv(envCheckpointDisable) != "") - // Create the profile loader + // Conditionally begin migrating any existing skills that match an older version to the embedded version. + var migration *skills.Migration + if !isDryRun(args) && os.Getenv(envSkipMigrate) == "" { + migration = skills.StartMigration(shutdownCtx) + } + + // Create the profile loader and load the active profile. loader, err := profile.NewLoader() if err != nil { fmt.Fprintln(io.Err(), err) @@ -155,19 +200,18 @@ func realMain() int { }, } - onlyFlagsInArgs := true - for _, arg := range args { - if !strings.HasPrefix(arg, "-") { - onlyFlagsInArgs = false - break + // Override the hashicorp/cli behavior of `tfctl --version` by rewriting the arguments to invoke the + // hidden "version" command. It's important not to call c.IsVersion() here because that would + // init the args, making overwriting them ineffective. + if isVersion(c.Args) || len(c.Args) == 0 { + newArgs := []string{"version"} + for _, arg := range c.Args { + // Strip all the possible version flags from the arguments + if arg != "--version" && arg != "-version" && arg != "-v" { + newArgs = append(newArgs, arg) + } } - } - - // If the user is running the root command, without --help or --version - // show the banner and exit. - if !c.IsVersion() && !c.IsHelp() && onlyFlagsInArgs { - showBanner(io) - return 0 + c.Args = newArgs } status, err := c.Run() @@ -175,52 +219,35 @@ func realMain() int { fmt.Fprintf(io.Err(), "Error executing %s: %s\n", version.Name, err.Error()) } - if status == 0 && c.IsVersion() { - checkForNewVersion(io) - } - - // Don't worry about telemetry errors at all - if err = tel.Shutdown(shutdownCtx, status); err != nil { - logger.Debug("Error occurred while shutting down telemetry", "error", err) - } + shutdownMain(shutdownCtx, status, migration) return status } -func showBanner(io iostreams.IOStreams) { - if io.ColorEnabled() && io.IsOutputTTY() { - cs := io.ColorScheme() - // Prepends two spaces before every line of the logo and after the final line - fmt.Fprintf(io.ErrUnessential(), " %s", strings.Join(strings.Split(Logo, "\n"), "\n ")) - fmt.Fprintf(io.ErrUnessential(), "%s\n", cs.String(version.Version).Color(cs.Purple()).Bold()) - fmt.Fprintln(io.ErrUnessential(), "") - } else { - fmt.Fprintln(io.ErrUnessential(), version.Version) - } - - fmt.Fprintln(io.Err(), heredoc.New(io).Mustf(`Get started by running {{ template "mdCodeOrBold" "%s auth login" }} -to authenticate with your user account or run {{ template "mdCodeOrBold" "%s --help" }} for usage -information. Release notes for this version are available at -{{ template "mdCodeOrBold" "https://github.com/hashicorp/tfctl-cli/blob/%s/CHANGELOG.md" }} -`, version.Name, version.Name, version.Version)) - fmt.Fprintln(io.Err(), "") +func shutdownMain(ctx context.Context, exitCode int, migration *skills.Migration) { + logger := logging.FromContext(ctx) + tel := telemetry.FromContext(ctx) - checkForNewVersion(io) -} + // Wait for any ongoing skill migrations to complete + if migration != nil { + migrationResults, err := migration.Wait(ctx) + if err != nil { + logger.Debug("Skipped skill migration", "error", err) + } -func checkForNewVersion(io iostreams.IOStreams) { - cs := io.ColorScheme() - versionInfo := checkpoint.WaitForVersionCheck() - if versionInfo.Outdated { - fmt.Fprintf(io.ErrUnessential(), "A new version of %s is available: %s\n", version.Name, cs.String(fmt.Sprintf("v%s", versionInfo.Latest)).Color(cs.Purple()).Bold()) - } - if len(versionInfo.Alerts) > 0 { - fmt.Fprintln(io.ErrUnessential(), "") - fmt.Fprintf(io.ErrUnessential(), "%s: %s\n", cs.WarningLabel(), "There are alerts regarding your current version.") - for _, alert := range versionInfo.Alerts { - fmt.Fprintln(io.ErrUnessential(), heredoc.New(io, heredoc.WithNoWrap()).Mustf(" - %s", alert)) + for _, result := range migrationResults { + if result.FailedReason != nil { + logger.Error("Failed to migrate skill", "path", result.SkillPath, "reason", result.FailedReason.Error()) + } else { + logger.Debug("Migrated skill", "path", result.SkillPath, "from", result.PreviousVersion) + } } } + + // Don't worry about telemetry errors at all + if err := tel.Shutdown(ctx, exitCode); err != nil { + logger.Debug("Error occurred while shutting down telemetry", "error", err) + } } // loadActiveProfile loads the active profile. diff --git a/go.mod b/go.mod index c03af22..c61a3aa 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/blugelabs/bluge v0.2.2 github.com/cli/browser v1.3.0 github.com/dustin/go-humanize v1.0.1 - github.com/getkin/kin-openapi v0.137.0 + github.com/getkin/kin-openapi v0.145.0 github.com/google/uuid v1.6.0 github.com/hashicorp/cli v1.1.7 github.com/hashicorp/go-checkpoint v0.5.0 @@ -71,8 +71,9 @@ require ( github.com/fatih/color v1.18.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/jsonpointer v0.22.5 // indirect + github.com/go-openapi/swag/jsonname v0.25.5 // indirect + github.com/go-test/deep v1.0.8 // indirect github.com/golang/snappy v0.0.1 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect @@ -81,10 +82,8 @@ require ( github.com/hashicorp/go-uuid v1.0.0 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/itchyny/timefmt-go v0.1.8 // indirect - github.com/josharian/intern v1.0.0 // indirect github.com/klauspost/compress v1.15.2 // indirect github.com/lucasb-eyer/go-colorful v1.3.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.19 // indirect @@ -95,18 +94,15 @@ require ( github.com/microsoft/kiota-serialization-text-go v1.1.3 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mschoch/smat v0.2.0 // indirect - github.com/oasdiff/yaml v0.0.9 // indirect - github.com/oasdiff/yaml3 v0.0.12 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/oasdiff/yaml v0.1.1 // indirect + github.com/oasdiff/yaml3 v0.0.14 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/spf13/cast v1.7.0 // indirect github.com/std-uritemplate/std-uritemplate/go/v2 v2.0.10 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 // indirect go.opentelemetry.io/otel/metric v1.44.0 // indirect diff --git a/go.sum b/go.sum index 323d545..150c140 100644 --- a/go.sum +++ b/go.sum @@ -85,17 +85,19 @@ github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/getkin/kin-openapi v0.137.0 h1:Q3HhawNQV0GfvO2mIYMUBUSEFrDsVlzcYz4VydL9YEo= -github.com/getkin/kin-openapi v0.137.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY= +github.com/getkin/kin-openapi v0.145.0 h1:htBX+Q7SevVaCUqymFegUKzH2WCbewl9tsmyn2FMGWY= +github.com/getkin/kin-openapi v0.145.0/go.mod h1:3BH9M9XDe/y9M5DSvEocVYAYq1w0qrhJHjC/vZi0AaY= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA= +github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0= +github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo= +github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU= +github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM= +github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= @@ -140,8 +142,6 @@ github.com/itchyny/gojq v0.12.19 h1:ttXA0XCLEMoaLOz5lSeFOZ6u6Q3QxmG46vfgI4O0DEs= github.com/itchyny/gojq v0.12.19/go.mod h1:5galtVPDywX8SPSOrqjGxkBeDhSxEW1gSxoy7tn1iZY= github.com/itchyny/timefmt-go v0.1.8 h1:1YEo1JvfXeAHKdjelbYr/uCuhkybaHCeTkH8Bo791OI= github.com/itchyny/timefmt-go v0.1.8/go.mod h1:5E46Q+zj7vbTgWY8o5YkMeYb4I6GeWLFnetPy5oBrAI= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/klauspost/compress v1.15.2 h1:3WH+AG7s2+T8o3nrM/8u2rdqUEcQhmga7smjrT41nAw= github.com/klauspost/compress v1.15.2/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= @@ -156,8 +156,6 @@ github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= @@ -192,8 +190,6 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= @@ -202,13 +198,11 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= -github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48= -github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM= -github.com/oasdiff/yaml3 v0.0.12 h1:75urAtPeDg2/iDEWwzNrLOWxI9N/dCh81nTTJtokt2M= -github.com/oasdiff/yaml3 v0.0.12/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/oasdiff/yaml v0.1.1 h1:6nHx+pn9gBRM6YpBlFZFQGCCd1nuvqOBtTD3KKTgGxY= +github.com/oasdiff/yaml v0.1.1/go.mod h1:EYJNoyktvWMJ0Hmhx+6qTaqMOsalUaRGT8Sj1hNcegU= +github.com/oasdiff/yaml3 v0.0.14 h1:aLJee3hxBK2H5wdXd9iPcIXb93Nty1Ge0pT171eHtkw= +github.com/oasdiff/yaml3 v0.0.14/go.mod h1:csto2xfDjYccdUn/yw/bPjj/cYTdp6HtFA0J4TWG+gg= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= -github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -245,10 +239,6 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= -github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/zclconf/go-cty v1.16.3 h1:osr++gw2T61A8KVYHoQiFbFd1Lh3JOCXc/jFLJXKTxk= github.com/zclconf/go-cty v1.16.3/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= diff --git a/internal/commands/api/api_test.go b/internal/commands/api/api_test.go index b6279fd..1372884 100644 --- a/internal/commands/api/api_test.go +++ b/internal/commands/api/api_test.go @@ -632,13 +632,13 @@ func TestRunAPI_DeleteQuietMode(t *testing.T) { // fakeAuthorizer is a programmable execsession.Authorizer for tests. type fakeAuthorizer struct { - decision execsession.Decision - err error - gotClasses []string + decision execsession.Decision + err error + gotTypes []string } func (f *fakeAuthorizer) AuthorizeDelete(class string) (execsession.Decision, error) { - f.gotClasses = append(f.gotClasses, class) + f.gotTypes = append(f.gotTypes, class) return f.decision, f.err } @@ -666,7 +666,7 @@ func TestRunAPI_DeleteAuthorizedBySession(t *testing.T) { // The request was actually sent (no prompt), and the class was evaluated. require.Equal(t, http.MethodDelete, recorder.Last().Method) - require.Equal(t, []string{"workspaces"}, auth.gotClasses) + require.Equal(t, []string{"workspaces"}, auth.gotTypes) // An audit notice is written to stderr. require.Contains(t, io.Error.String(), "authorized by exec session") } @@ -765,7 +765,7 @@ func TestRunAPI_DeleteAuthorizedSessionSkipsRequestInDryRun(t *testing.T) { })) require.NoError(t, err) // Permission is still evaluated, but no request is sent in dry-run. - require.Equal(t, []string{"workspaces"}, auth.gotClasses) + require.Equal(t, []string{"workspaces"}, auth.gotTypes) require.Empty(t, recorder.All()) require.Contains(t, io.Error.String(), "would send DELETE") } diff --git a/internal/commands/create/create.go b/internal/commands/create/create.go index a94de45..fff135c 100644 --- a/internal/commands/create/create.go +++ b/internal/commands/create/create.go @@ -120,7 +120,7 @@ func runCreate(ctx context.Context, opts *Opts) error { } resourceArg := opts.Args[0] - res := resource.ByName(resourceArg) + res := resource.ByNameOrAlias(resourceArg) if res == nil { return fmt.Errorf("unknown resource type: %q\nAvailable resources: %s", resourceArg, strings.Join(resource.Names(), ", ")) diff --git a/internal/commands/get/get.go b/internal/commands/get/get.go index 5829625..61e40b6 100644 --- a/internal/commands/get/get.go +++ b/internal/commands/get/get.go @@ -148,7 +148,7 @@ func runGet(ctx context.Context, opts *Opts) error { func runGetSingleArg(ctx context.Context, opts *Opts, arg string) error { // Check if arg is a known resource type name (list mode). - if res := resource.ByName(arg); res != nil { + if res := resource.ByNameOrAlias(arg); res != nil { return runList(ctx, opts, res) } @@ -167,7 +167,7 @@ func runGetSingleArg(ctx context.Context, opts *Opts, arg string) error { } func runGetTwoArgs(ctx context.Context, opts *Opts, resourceArg, id string) error { - res := resource.ByName(resourceArg) + res := resource.ByNameOrAlias(resourceArg) if res == nil { return fmt.Errorf("unknown resource type: %q\nAvailable resources: %s", resourceArg, strings.Join(resource.Names(), ", ")) diff --git a/internal/commands/harness/harness_exec.go b/internal/commands/harness/harness_exec.go index 6dd2888..d3ea986 100644 --- a/internal/commands/harness/harness_exec.go +++ b/internal/commands/harness/harness_exec.go @@ -48,8 +48,9 @@ func NewCmdHarnessExec(inv *cmd.Invocation) *cmd.Command { } command := &cmd.Command{ - Name: "exec", - ShortHelp: "Run a command with session-scoped tfctl permissions.", + Name: "exec", + NoAuthRequired: true, + ShortHelp: "Run a command with session-scoped tfctl permissions.", LongHelp: heredoc.New(inv.IO, heredoc.WithPreserveNewlines()).Mustf(` The {{ template "mdCodeOrBold" "%s harness exec" }} command runs a child command (such as a coding agent) with a short-lived, session-scoped permission that lets nested {{ Bold "tfctl" }} invocations perform noninteractive deletes. @@ -57,21 +58,20 @@ func NewCmdHarnessExec(inv *cmd.Invocation) *cmd.Command { This is a {{ Bold "safety rail, not a security boundary" }}: the child runs as the same OS user, so a true guarantee that an agent cannot delete must come from the API token scope server-side. - Use {{ template "mdCodeOrBold" "--allow-delete" }} to name the resource classes that may be deleted noninteractively. Repeat the flag or pass a comma-separated list. The special tokens {{ template "mdCodeOrBold" "reversible" }} and {{ template "mdCodeOrBold" "all" }} cover any reversible class, but {{ Bold "never" }} cover the irreversible classes {{ template "mdCodeOrBold" "organizations" }} and {{ template "mdCodeOrBold" "projects" }} — those must always be named explicitly. + Use {{ template "mdCodeOrBold" "--allow-delete" }} to name the resource types that may be deleted noninteractively. Only resource types that are explicitly named may be deleted noninteractively. Repeat the flag or pass a comma-separated list. The child command and its arguments must follow a {{ template "mdCodeOrBold" "--" }} separator. `, version.Name), Examples: []cmd.Example{ { - Preamble: "Allow an agent to delete workspaces and runs for one session:", - Command: "$ tfctl harness exec --allow-delete=workspaces,runs -- opencode", + Preamble: "Allow an agent to delete workspaces and vars for one session:", + Command: "$ tfctl harness exec --allow-delete=workspaces,vars -- opencode", }, { - Preamble: "Explicitly allow deleting projects (an irreversible class):", + Preamble: "Explicitly allow deleting projects (an irreversible action!):", Command: "$ tfctl harness exec --allow-delete=projects -- ./ci-script.sh", }, }, - NoAuthRequired: true, Args: cmd.PositionalArguments{ // The child command + args are passed through verbatim; bypass count // validation and enforce "at least one" inside runExec so we can emit @@ -99,8 +99,8 @@ func NewCmdHarnessExec(inv *cmd.Invocation) *cmd.Command { Local: []*cmd.Flag{ { Name: "allow-delete", - DisplayValue: "CLASSES", - Description: "Resource classes that nested tfctl may delete noninteractively (repeatable, CSV). Special tokens: reversible, all. organizations/projects must be named explicitly.", + DisplayValue: "RESOURCE_TYPES", + Description: "Resource types that nested processes may delete noninteractively (repeatable, CSV). Use with caution.", Repeatable: true, Value: flagvalue.SimpleSlice(nil, &execOpts.AllowDelete), Autocomplete: complete.PredictSet(execsession.AllowDeleteCompletions()...), @@ -131,7 +131,7 @@ func runExec(ctx context.Context, opts *ExecOpts) error { cs := opts.IO.ColorScheme() if len(opts.Argv) == 0 { - return errors.New("no command to run; usage: tfctl harness exec [--allow-delete=CLASSES] -- [args...]") + return errors.New("no command to run; usage: tfctl harness exec [--allow-delete=RESOURCE_TYPES] -- [args...]") } perms, warnings := execsession.NormalizeAllowDelete(opts.AllowDelete) @@ -156,7 +156,7 @@ func runExec(ctx context.Context, opts *ExecOpts) error { }() logger.Debug("exec session created", "allow_delete", perms) - fmt.Fprintf(opts.IO.Err(), "%s tfctl deletes enabled for this session: %v\n", cs.WarningLabel(), perms) + fmt.Fprintln(opts.IO.Err(), heredoc.New(opts.IO, heredoc.WithNoWrap()).Mustf(`%s %s allows non-interactive deletes in this session for these types: {{ template "mdCodeOrBold" "%s" }}`, cs.WarningLabel(), version.Name, strings.Join(perms, ", "))) env := append(os.Environ(), execsession.EnvVar+"="+handle.Token()) code, runErr := opts.Run(ctx, opts.Argv, env, opts.IO) diff --git a/internal/commands/harness/harness_install.go b/internal/commands/harness/harness_install.go index d3ab0ac..6d8a4d1 100644 --- a/internal/commands/harness/harness_install.go +++ b/internal/commands/harness/harness_install.go @@ -40,8 +40,9 @@ func NewCmdHarnessInstall(inv *cmd.Invocation) *cmd.Command { listAgentsSentence := fmt.Sprintf("%s, or %s", strings.Join(skills.AgentNames[:len(skills.AgentNames)-1], ", "), skills.AgentNames[len(skills.AgentNames)-1]) cmd := &cmd.Command{ - Name: "install", - ShortHelp: "Install coding agent skills for tfctl.", + Name: "install", + NoAuthRequired: true, + ShortHelp: "Install coding agent skills for tfctl.", LongHelp: heredoc.New(inv.IO, heredoc.WithPreserveNewlines()).Mustf(` The {{ template "mdCodeOrBold" "%s harness install" }} command installs the official tfctl agent skill for the selected platform. The available agent platforms are: {{ template "mdCodeOrBold" "%s" }}. diff --git a/internal/commands/root/root.go b/internal/commands/root/root.go index 3537324..b556581 100644 --- a/internal/commands/root/root.go +++ b/internal/commands/root/root.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/tfctl-cli/internal/commands/profile" "github.com/hashicorp/tfctl-cli/internal/commands/run" "github.com/hashicorp/tfctl-cli/internal/commands/variable" + "github.com/hashicorp/tfctl-cli/internal/commands/versioncmd" "github.com/hashicorp/tfctl-cli/internal/pkg/cmd" "github.com/hashicorp/tfctl-cli/version" ) @@ -45,6 +46,7 @@ func NewCmdRoot(inv *cmd.Invocation) *cmd.Command { c.AddChild(variable.NewCmdVariable(inv)) c.AddChild(profile.NewCmdProfile(inv)) c.AddChild(harness.NewCmdHarness(inv)) + c.AddChild(versioncmd.NewCmdVersion(inv)) // Configure the command as the root command. cmd.ConfigureRootCommand(inv, c) diff --git a/cmd/tfctl/logo.txt b/internal/commands/versioncmd/logo.txt similarity index 100% rename from cmd/tfctl/logo.txt rename to internal/commands/versioncmd/logo.txt diff --git a/internal/commands/versioncmd/versioncmd.go b/internal/commands/versioncmd/versioncmd.go new file mode 100644 index 0000000..ca165c0 --- /dev/null +++ b/internal/commands/versioncmd/versioncmd.go @@ -0,0 +1,105 @@ +// Copyright IBM Corp. 2026 +// SPDX-License-Identifier: MPL-2.0 + +// Package versioncmd provides the hidden version command for the tfctl CLI, +// which is invoked using `--version`, `-v`, or `version` +package versioncmd + +import ( + "context" + _ "embed" + "fmt" + "strings" + + "github.com/hashicorp/tfctl-cli/internal/pkg/checkpoint" + "github.com/hashicorp/tfctl-cli/internal/pkg/cmd" + "github.com/hashicorp/tfctl-cli/internal/pkg/heredoc" + "github.com/hashicorp/tfctl-cli/internal/pkg/iostreams" + "github.com/hashicorp/tfctl-cli/version" +) + +//go:embed logo.txt +var logo string + +// VersionOpts contains the options for running the banner command. +type VersionOpts struct { + IO iostreams.IOStreams + TokenConfigured bool +} + +// NewCmdVersion creates the hidden version command. +func NewCmdVersion(inv *cmd.Invocation) *cmd.Command { + opts := &VersionOpts{ + IO: inv.IO, + } + + c := &cmd.Command{ + Hidden: true, + Name: "version", + ShortHelp: "Shows the current version.", + LongHelp: heredoc.New(inv.IO).Mustf(`Shows the current version, checks for newer CLI versions and outdated skill installations.`), + Flags: cmd.Flags{ + Local: []*cmd.Flag{}, + }, + NoAuthRequired: true, + RunF: func(_ *cmd.Command, _ []string) error { + opts.TokenConfigured = inv.Profile != nil && inv.Profile.GetToken() != "" + + runVersion(inv.ShutdownCtx, opts) + return nil + }, + } + return c +} + +// runDetectOutdatedVersion checks if the current CLI version is outdated and prints relevant messages. +func runDetectOutdatedVersion(_ context.Context, io iostreams.IOStreams) { + cs := io.ColorScheme() + versionInfo := checkpoint.WaitForVersionCheck() + + if versionInfo != nil { + fmt.Fprintln(io.ErrUnessential()) + + if versionInfo.Outdated { + fmt.Fprintf(io.ErrUnessential(), "A new version of %s is available: %s\n", version.Name, cs.String(fmt.Sprintf("v%s", versionInfo.Latest)).Color(cs.Purple()).Bold()) + fmt.Fprintln(io.ErrUnessential()) + } else { + fmt.Fprintln(io.ErrUnessential(), heredoc.New(io).Mustf(`Release notes for this version are available at + {{ template "mdCodeOrBold" "https://github.com/hashicorp/tfctl-cli/blob/%s/CHANGELOG.md" }}`, version.Version)) + fmt.Fprintln(io.ErrUnessential()) + } + + if len(versionInfo.Alerts) > 0 { + fmt.Fprintln(io.ErrUnessential(), "") + fmt.Fprintf(io.ErrUnessential(), "%s: %s\n", cs.WarningLabel(), "There are alerts regarding your current version.") + for _, alert := range versionInfo.Alerts { + fmt.Fprintln(io.ErrUnessential(), heredoc.New(io, heredoc.WithNoWrap()).Mustf(" - %s", alert)) + } + } + } +} + +// runVersion displays the banner with the logo and version information. +func runVersion(ctx context.Context, opts *VersionOpts) { + // Implementation for displaying the version information/banner goes here. + io := opts.IO + cs := io.ColorScheme() + + if io.ColorEnabled() && io.IsOutputTTY() { + // Prepends two spaces before every line of the logo and after the final line + fmt.Fprintf(io.ErrUnessential(), " %s", strings.Join(strings.Split(logo, "\n"), "\n ")) + fmt.Fprintf(io.Err(), "%s\n", cs.String(version.Version).Color(cs.Purple()).Bold()) + fmt.Fprintln(io.ErrUnessential(), "") + } else { + fmt.Fprintln(io.Err(), version.Version) + } + + if !opts.TokenConfigured { + fmt.Fprintln(io.ErrUnessential(), heredoc.New(io).Mustf(`Get started by running {{ template "mdCodeOrBold" "%s auth login" }} +to authenticate with your user account or run {{ template "mdCodeOrBold" "%s --help" }} for usage +information. +`, version.Name, version.Name)) + } + + runDetectOutdatedVersion(ctx, io) +} diff --git a/internal/commands/versioncmd/versioncmd_test.go b/internal/commands/versioncmd/versioncmd_test.go new file mode 100644 index 0000000..3a74dad --- /dev/null +++ b/internal/commands/versioncmd/versioncmd_test.go @@ -0,0 +1,124 @@ +// Copyright IBM Corp. 2026 +// SPDX-License-Identifier: MPL-2.0 + +package versioncmd + +import ( + "context" + "strings" + "testing" + + "github.com/hashicorp/tfctl-cli/internal/pkg/checkpoint" + "github.com/hashicorp/tfctl-cli/internal/pkg/iostreams" + "github.com/hashicorp/tfctl-cli/version" +) + +// seedCheckpoint pre-fills the checkpoint channel with nil (disabled) so that +// WaitForVersionCheck returns immediately. Tests that call runVersion or +// runDetectOutdatedVersion must call seedCheckpoint first. +func seedCheckpoint(t *testing.T) { + t.Helper() + checkpoint.Run(context.Background(), true) +} + +func TestRunVersion_NoToken_PrintsVersionAndAuthHint(t *testing.T) { + seedCheckpoint(t) + + ios := iostreams.Test() + opts := &VersionOpts{IO: ios, TokenConfigured: false} + + runVersion(context.Background(), opts) + + errOut := ios.Error.String() + if !strings.Contains(errOut, version.Version) { + t.Errorf("expected version %q in error output, got:\n%s", version.Version, errOut) + } + if !strings.Contains(errOut, "auth login") { + t.Errorf("expected 'auth login' hint in error output, got:\n%s", errOut) + } + if !strings.Contains(errOut, version.Name) { + t.Errorf("expected CLI name %q in error output, got:\n%s", version.Name, errOut) + } +} + +func TestRunVersion_NoToken_VersionOnFirstLine(t *testing.T) { + seedCheckpoint(t) + + ios := iostreams.Test() + opts := &VersionOpts{IO: ios, TokenConfigured: false} + + runVersion(context.Background(), opts) + + // With Testing IOStreams, ColorEnabled() always returns false, so the non-TTY + // path runs: version.Version is written to Err() as the very first line. + errOut := ios.Error.String() + lines := strings.Split(strings.TrimSpace(errOut), "\n") + if lines[0] != version.Version { + t.Errorf("expected first line of error output to be %q, got %q", version.Version, lines[0]) + } +} + +func TestRunVersion_TokenConfigured_NoAuthHint(t *testing.T) { + seedCheckpoint(t) + + ios := iostreams.Test() + opts := &VersionOpts{IO: ios, TokenConfigured: true} + + runVersion(context.Background(), opts) + + errOut := ios.Error.String() + if strings.Contains(errOut, "auth login") { + t.Errorf("expected no 'auth login' hint when token is configured, got:\n%s", errOut) + } + if !strings.Contains(errOut, version.Version) { + t.Errorf("expected version %q in error output, got:\n%s", version.Version, errOut) + } +} + +func TestRunVersion_NoOutput_ToStdout(t *testing.T) { + seedCheckpoint(t) + + ios := iostreams.Test() + opts := &VersionOpts{IO: ios, TokenConfigured: false} + + runVersion(context.Background(), opts) + + if ios.Output.Len() != 0 { + t.Errorf("expected no output on stdout, got:\n%s", ios.Output.String()) + } +} + +func TestRunVersion_Quiet_VersionStillPrinted(t *testing.T) { + seedCheckpoint(t) + + ios := iostreams.Test() + ios.SetQuiet(true) + opts := &VersionOpts{IO: ios, TokenConfigured: false} + + runVersion(context.Background(), opts) + + // Err() is always written (not suppressed by quiet mode) — version must appear. + errOut := ios.Error.String() + if !strings.Contains(errOut, version.Version) { + t.Errorf("expected version %q in error output even in quiet mode, got:\n%s", version.Version, errOut) + } +} + +func TestRunVersion_Quiet_LogoSuppressed(t *testing.T) { + seedCheckpoint(t) + + ios := iostreams.Test() + ios.SetQuiet(true) + opts := &VersionOpts{IO: ios, TokenConfigured: false} + + runVersion(context.Background(), opts) + + // The logo is written to ErrUnessential(), which is discarded in quiet mode. + // Logo lines are each prefixed with two spaces. Count them to confirm suppression. + errOut := ios.Error.String() + for _, line := range strings.Split(errOut, "\n") { + if strings.HasPrefix(line, " /") || strings.HasPrefix(line, " \\") { + t.Errorf("expected logo to be suppressed in quiet mode, got indented line:\n%s", line) + } + } +} diff --git a/internal/pkg/checkpoint/checkpoint.go b/internal/pkg/checkpoint/checkpoint.go index 03f3f82..3e96f77 100644 --- a/internal/pkg/checkpoint/checkpoint.go +++ b/internal/pkg/checkpoint/checkpoint.go @@ -63,13 +63,12 @@ func Run(ctx context.Context, disabled bool) { } // WaitForVersionCheck waits for the result of a Checkpoint request and returns -// the version information. If the request failed, it returns an empty VersionCheckInfo. -func WaitForVersionCheck() VersionCheckInfo { +// the version information. If the request failed, it returns nil. +func WaitForVersionCheck() *VersionCheckInfo { // Wait for the result to come through info := <-checkpointResult if info == nil { - var zero VersionCheckInfo - return zero + return nil } // Build the alerts that we may have received about our version @@ -78,9 +77,11 @@ func WaitForVersionCheck() VersionCheckInfo { alerts[i] = a.Message } - return VersionCheckInfo{ + checkInfo := VersionCheckInfo{ Outdated: info.Outdated, Latest: info.CurrentVersion, Alerts: alerts, } + + return &checkInfo } diff --git a/internal/pkg/execsession/execsession.go b/internal/pkg/execsession/execsession.go index bd40688..a8a139a 100644 --- a/internal/pkg/execsession/execsession.go +++ b/internal/pkg/execsession/execsession.go @@ -60,8 +60,7 @@ var tokenEncoding = base32.StdEncoding.WithPadding(base32.NoPadding) // Permissions is the set of capabilities granted to a session. type Permissions struct { - // AllowDelete holds normalized resource classes, and may contain the - // reversible/all sentinels. + // AllowDelete holds normalized resource types. AllowDelete []string } @@ -247,7 +246,7 @@ type LivenessFn func(path string) (alive bool, err error) // EnvAuthorizer is the runtime Authorizer. It reads the session token from the // environment, loads the session, and verifies the granting process is still -// alive before checking the granted classes. +// alive before checking the granted types. type EnvAuthorizer struct { Store *Store Getenv func(string) string // default os.Getenv diff --git a/internal/pkg/execsession/execsession_test.go b/internal/pkg/execsession/execsession_test.go index 7b8e29b..3607b4f 100644 --- a/internal/pkg/execsession/execsession_test.go +++ b/internal/pkg/execsession/execsession_test.go @@ -215,20 +215,6 @@ func TestEnvAuthorizerAuthorizeDelete(t *testing.T) { assert.Equal(t, token, d.Token) }) - t.Run("irreversible class with only reversible grant is denied", func(t *testing.T) { - t.Parallel() - store, token := newStoreWithSession(t, Permissions{AllowDelete: []string{SentinelReversible}}, 4242) - a := &EnvAuthorizer{ - Store: store, - Getenv: func(string) string { return token }, - Liveness: fakeLiveness(true), - } - d, err := a.AuthorizeDelete("projects") - require.NoError(t, err) - assert.False(t, d.Allowed) - assert.Equal(t, ReasonClassNotGranted, d.Reason) - }) - t.Run("liveness probe error is surfaced", func(t *testing.T) { t.Parallel() store, token := newStoreWithSession(t, Permissions{AllowDelete: []string{"workspaces"}}, 4242) diff --git a/internal/pkg/execsession/permissions.go b/internal/pkg/execsession/permissions.go index a9f3b6c..7df009e 100644 --- a/internal/pkg/execsession/permissions.go +++ b/internal/pkg/execsession/permissions.go @@ -5,75 +5,27 @@ package execsession import ( "fmt" - "sort" "strings" -) - -// IrreversibleClasses are resource classes whose deletes cannot be undone, so -// they are NEVER covered by wildcards and must be named explicitly in -// --allow-delete. -var IrreversibleClasses = map[string]bool{ - "organizations": true, - "projects": true, -} -// KnownClasses is a best-effort set of resource classes that tfctl can delete. -// It is used only to warn (not hard-fail) when --allow-delete names something -// outside this set, because the API surface is large and evolving. -var KnownClasses = map[string]bool{ - "organizations": true, - "projects": true, - "workspaces": true, - "runs": true, - "vars": true, - "varsets": true, - "teams": true, - "team-workspaces": true, - "notification-configurations": true, - "configuration-versions": true, - "state-versions": true, - "policy-checks": true, - "policies": true, - "policy-sets": true, - "remote-state-consumers": true, - "oauth-clients": true, - "oauth-tokens": true, - "ssh-keys": true, - "agent-pools": true, - "registry-modules": true, - "registry-providers": true, -} - -// Sentinels accepted in --allow-delete that mean "any reversible class". "all" -// is treated identically to "reversible" on purpose so there is no footgun -// token that silently includes orgs/projects. -const ( - // SentinelReversible permits deletes of any reversible resource class. - SentinelReversible = "reversible" - - // SentinelAll is an alias for SentinelReversible. It does NOT cover - // irreversible classes. - SentinelAll = "all" + "github.com/hashicorp/tfctl-cli/internal/pkg/resource" ) // AllowDeleteCompletions returns the suggested values for --allow-delete: every -// known resource class plus the reversible/all sentinels, sorted and -// deduplicated. The irreversible classes are intentionally included so a human -// can tab-complete them when naming them explicitly (wildcards never cover -// them, but explicit grants are allowed). +// known destroyable resource class. func AllowDeleteCompletions() []string { - out := make([]string, 0, len(KnownClasses)+2) - out = append(out, SentinelReversible, SentinelAll) - for class := range KnownClasses { - out = append(out, class) + allResources := resource.All() + + out := make([]string, 0, len(allResources)) + for _, r := range allResources { + if r.Destroyable != resource.NotDestroyable { + out = append(out, r.Type) + } } - sort.Strings(out) return out } // AllowsDelete reports whether class is permitted by the granted set. Explicit -// class names always match (including irreversible classes). The reversible/all -// sentinels match any non-irreversible class. An empty/unknown class is always +// class names always match. An empty/unknown class is always // denied. func AllowsDelete(granted []string, class string) bool { for _, g := range granted { @@ -85,15 +37,19 @@ func AllowsDelete(granted []string, class string) bool { if class == "" { return false // unknown path -> deny } - if IrreversibleClasses[class] { - return false // wildcards never cover irreversible classes + + ponder, ok := resource.ByName(class) + if !ok { + // The class is unknown to this CLI, so it cannot be allowed. + return false } for _, g := range granted { - if g == SentinelReversible || g == SentinelAll { + if g == ponder.Type { return true } } + return false } @@ -148,28 +104,27 @@ func isAllDigits(s string) bool { } // NormalizeAllowDelete lowercases, trims, and CSV-splits the raw --allow-delete -// values into a normalized, deduplicated list of classes. Unknown classes (not -// in KnownClasses and not a sentinel) are returned as warnings but are still -// kept in the output, since the API surface is large. +// values into a normalized, deduplicated list of types. Unknown types (not +// are returned as warnings but are still kept in the output, since the API surface is large. func NormalizeAllowDelete(in []string) (out []string, warnings []string) { seen := make(map[string]bool) for _, raw := range in { for _, part := range strings.Split(raw, ",") { - class := strings.ToLower(strings.TrimSpace(part)) - if class == "" { + grant := strings.ToLower(strings.TrimSpace(part)) + if grant == "" { continue } - if seen[class] { - continue - } - seen[class] = true - out = append(out, class) - - if class == SentinelReversible || class == SentinelAll { + if seen[grant] { continue } - if !KnownClasses[class] { - warnings = append(warnings, fmt.Sprintf("unknown resource class %q in --allow-delete; it will be honored literally but may never match a delete path", class)) + seen[grant] = true + out = append(out, grant) + + found, ok := resource.ByName(grant) + if !ok { + warnings = append(warnings, fmt.Sprintf("unknown resource type %q in --allow-delete; it may still be honored", grant)) + } else if found.Destroyable == resource.NotDestroyable { + warnings = append(warnings, fmt.Sprintf("resource type %q in --allow-delete is known to be not destroyable and will never match a delete path", found.Type)) } } } diff --git a/internal/pkg/execsession/permissions_test.go b/internal/pkg/execsession/permissions_test.go index f18cabf..665df74 100644 --- a/internal/pkg/execsession/permissions_test.go +++ b/internal/pkg/execsession/permissions_test.go @@ -4,41 +4,36 @@ package execsession import ( - "sort" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/hashicorp/tfctl-cli/internal/pkg/resource" ) func TestAllowDeleteCompletions(t *testing.T) { t.Parallel() got := AllowDeleteCompletions() - - // The sentinels must be offered so a human can tab-complete them. - assert.Contains(t, got, SentinelReversible) - assert.Contains(t, got, SentinelAll) + all := resource.AllDestroyable() // Every known class must be offered, including the irreversible ones so a // human can explicitly name organizations/projects. - for class := range KnownClasses { - assert.Contains(t, got, class, "known class %q must be completable", class) + for class, r := range all { + assert.Contains(t, got, r.Type, "known class %q must be completable", class) } - assert.Contains(t, got, "organizations") - assert.Contains(t, got, "projects") // The result must be sorted and free of duplicates for deterministic // completion output. - assert.True(t, sort.StringsAreSorted(got), "completions must be sorted") seen := make(map[string]bool, len(got)) for _, c := range got { require.False(t, seen[c], "duplicate completion %q", c) seen[c] = true } - // Exactly the known classes plus the two sentinels, nothing else. - assert.Len(t, got, len(KnownClasses)+2) + // Exactly the known types, nothing else. + assert.Len(t, got, len(all)) } func TestClassFromPath(t *testing.T) { @@ -81,17 +76,8 @@ func TestAllowsDelete(t *testing.T) { }{ {name: "explicit class match", granted: []string{"workspaces"}, class: "workspaces", want: true}, {name: "explicit class no match", granted: []string{"workspaces"}, class: "runs", want: false}, - {name: "reversible covers workspaces", granted: []string{SentinelReversible}, class: "workspaces", want: true}, - {name: "all covers workspaces", granted: []string{SentinelAll}, class: "workspaces", want: true}, - {name: "reversible covers runs", granted: []string{SentinelReversible}, class: "runs", want: true}, - {name: "reversible does NOT cover organizations", granted: []string{SentinelReversible}, class: "organizations", want: false}, - {name: "reversible does NOT cover projects", granted: []string{SentinelReversible}, class: "projects", want: false}, - {name: "all does NOT cover organizations", granted: []string{SentinelAll}, class: "organizations", want: false}, - {name: "all does NOT cover projects", granted: []string{SentinelAll}, class: "projects", want: false}, {name: "explicit organizations allowed", granted: []string{"organizations"}, class: "organizations", want: true}, {name: "explicit projects allowed", granted: []string{"projects"}, class: "projects", want: true}, - {name: "explicit projects plus reversible", granted: []string{SentinelReversible, "projects"}, class: "projects", want: true}, - {name: "empty class denied even with all", granted: []string{SentinelAll}, class: "", want: false}, {name: "empty granted denied", granted: nil, class: "workspaces", want: false}, {name: "empty class empty granted", granted: nil, class: "", want: false}, } @@ -109,36 +95,22 @@ func TestNormalizeAllowDelete(t *testing.T) { t.Run("csv split and lowercase", func(t *testing.T) { t.Parallel() - out, warnings := NormalizeAllowDelete([]string{"Workspaces,RUNS"}) - assert.Equal(t, []string{"workspaces", "runs"}, out) + out, warnings := NormalizeAllowDelete([]string{"Workspaces,STACKS"}) + assert.Equal(t, []string{"workspaces", "stacks"}, out) assert.Empty(t, warnings) }) t.Run("trims whitespace", func(t *testing.T) { t.Parallel() - out, warnings := NormalizeAllowDelete([]string{" workspaces , runs "}) - assert.Equal(t, []string{"workspaces", "runs"}, out) - assert.Empty(t, warnings) - }) - - t.Run("sentinel passthrough", func(t *testing.T) { - t.Parallel() - out, warnings := NormalizeAllowDelete([]string{"reversible"}) - assert.Equal(t, []string{"reversible"}, out) - assert.Empty(t, warnings) - }) - - t.Run("all sentinel passthrough", func(t *testing.T) { - t.Parallel() - out, warnings := NormalizeAllowDelete([]string{"all"}) - assert.Equal(t, []string{"all"}, out) + out, warnings := NormalizeAllowDelete([]string{" workspaces , stacks "}) + assert.Equal(t, []string{"workspaces", "stacks"}, out) assert.Empty(t, warnings) }) t.Run("repeated flags", func(t *testing.T) { t.Parallel() - out, warnings := NormalizeAllowDelete([]string{"workspaces", "runs"}) - assert.Equal(t, []string{"workspaces", "runs"}, out) + out, warnings := NormalizeAllowDelete([]string{"workspaces", "stacks"}) + assert.Equal(t, []string{"workspaces", "stacks"}, out) assert.Empty(t, warnings) }) diff --git a/internal/pkg/openapi/spec/hcpt_v2_public_beta.json b/internal/pkg/openapi/spec/hcpt_v2_public_beta.json index 3f9a7a7..91ea92f 100644 --- a/internal/pkg/openapi/spec/hcpt_v2_public_beta.json +++ b/internal/pkg/openapi/spec/hcpt_v2_public_beta.json @@ -1,9 +1,9 @@ { "openapi": "3.0.0", "info": { - "version": "2.6.0", - "title": "HCP Terraform API v2-Beta", - "description": "OpenAPI Specification for the HCP Terraform API V2 Public Beta.", + "version": "ee6a78eb", + "title": "HCP Terraform/Terraform Enterprise API v2-Beta", + "description": "OpenAPI Specification for the HCP Terraform/Terraform Enterprise API V2 Public Beta.", "license": { "name": "MPL-2.0", "url": "https://www.mozilla.org/en-US/MPL/2.0/" @@ -13,11 +13,6 @@ "url": "https://developer.hashicorp.com/terraform/cloud-docs/api-docs" } }, - "servers": [ - { - "url": "https://app.terraform.io/api/v2" - } - ], "security": [ { "bearerAuth": [] @@ -100,6 +95,14 @@ "url": "https://developer.hashicorp.com/terraform/cloud-docs/api-docs/configuration-versions" } }, + { + "name": "data-retention-policies", + "x-vis": [ + "tfe" + ], + "x-displayName": "Data Retention Policies", + "description": "Data Retention Policy actions" + }, { "name": "organizations", "x-displayName": "Organizations", @@ -137,6 +140,14 @@ "url": "https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces" } }, + { + "name": "provider-sets", + "x-displayName": "Provider Sets", + "description": "Provider set management for organizations, projects, and workspaces", + "x-vis": [ + "public-beta" + ] + }, { "name": "varsets", "x-displayName": "Variable Sets", @@ -153,6 +164,14 @@ "url": "https://developer.hashicorp.com/terraform/cloud-docs/registry" } }, + { + "name": "hyok", + "x-vis": [ + "hcpt" + ], + "x-displayName": "HYOK", + "description": "HYOK Configuration actions and key data" + }, { "name": "runs", "x-displayName": "Runs", @@ -193,6 +212,14 @@ "url": "https://developer.hashicorp.com/terraform/cloud-docs/api-docs/policy-checks" } }, + { + "name": "tf-policy-evaluations", + "x-vis": [ + "public-beta" + ], + "x-displayName": "Terraform Policy Evaluations", + "description": "Terraform Policy evaluation actions and outcomes for runs.\n\n**Note:** These APIs are in public beta and are available in HCP Terraform only.\n" + }, { "name": "policy-set-params", "x-displayName": "Policy Set Parameters", @@ -307,6 +334,17 @@ "url": "https://developer.hashicorp.com/terraform/cloud-docs/users-teams-organizations/api-tokens" } }, + { + "name": "metrics-tokens", + "x-vis": [ + "hcpt" + ], + "x-displayName": "Metrics Tokens", + "description": "Metrics Service tokens API", + "externalDocs": { + "url": "https://developer.hashicorp.com/terraform/cloud-docs/api-docs/metrics-service-tokens" + } + }, { "name": "users", "x-displayName": "Users", @@ -407,6 +445,11 @@ "name": "workspace-transfers", "x-displayName": "Workspace Transfers", "description": "Transfer workspaces across organizations" + }, + { + "name": "tag-binding", + "x-displayName": "Tag Bindings", + "description": "Tag bindings on resources" } ], "paths": { @@ -568,7 +611,7 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/users" + "$ref": "#/components/schemas/users-envelope" } } } @@ -596,7 +639,7 @@ "tags": [ "accounts" ], - "description": "Get details of a specific HCP organization", + "description": "Get details of a specific HCP organization\n\nThis operation is only available in HCP Terraform.", "parameters": [ { "name": "hcp_organization_id", @@ -656,7 +699,7 @@ ], "get": { "summary": "List Feature Sets", - "description": "Lists the feature sets available in HCP Terraform. Returns feature sets that are active, current, and public.", + "description": "Lists the feature sets available in HCP Terraform. Returns feature sets that are active, current, and public.\n\nThis operation is only available in HCP Terraform.", "operationId": "listFeatureSets", "tags": [ "feature-sets" @@ -728,7 +771,7 @@ ], "get": { "summary": "List Feature Sets for Organization", - "description": "Lists the feature sets a particular organization is eligible to access.", + "description": "Lists the feature sets a particular organization is eligible to access.\n\nThis operation is only available in HCP Terraform.", "operationId": "listOrganizationFeatureSets", "tags": [ "feature-sets" @@ -820,7 +863,7 @@ "get": { "operationId": "showSubscription", "summary": "Show a subscription", - "description": "Show details of a subscription.", + "description": "Show details of a subscription.\n\nThis operation is only available in HCP Terraform.", "tags": [ "subscriptions" ], @@ -859,6 +902,93 @@ } } }, + "/organizations/{organization_name}/subscription": { + "x-vis": [ + "hcpt" + ], + "patch": { + "operationId": "updateOrganizationSubscription", + "summary": "Update organization subscription", + "description": "Update configurable fields on an organization's active subscription. Currently supports setting, updating, or clearing the RUM alert threshold. Requires org owner permissions. Only available on paid RUM plans.\n\n\nThis operation is only available in HCP Terraform.", + "tags": [ + "subscriptions" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the organization." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "subscriptions" + ] + }, + "attributes": { + "type": "object", + "properties": { + "rum-alert-threshold": { + "type": "integer", + "nullable": true, + "minimum": 0, + "description": "The RUM usage alert threshold. When the organization's billable resource count meets or exceeds this value, an alert email is sent to org owners. Send null or 0 to clear the threshold and disable alerting.\n" + } + } + } + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Subscription updated", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/subscriptions-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, "/organizations/{organization_name}/invoices": { "x-vis": [ "hcpt" @@ -866,7 +996,7 @@ "get": { "operationId": "listOrganizationInvoices", "summary": "List organization invoices", - "description": "Lists the previous invoices for an organization. This endpoint uses cursor-based pagination with a fixed page size of 10 items. Pass the value of meta.continuation as the cursor parameter to retrieve the next page. When meta.continuation is null there are no further pages.", + "description": "Lists the previous invoices for an organization. This endpoint uses cursor-based pagination with a fixed page size of 10 items. Pass the value of meta.continuation as the cursor parameter to retrieve the next page. When meta.continuation is null there are no further pages.\n\nThis operation is only available in HCP Terraform.", "tags": [ "billing-invoices" ], @@ -942,7 +1072,7 @@ "get": { "operationId": "showOrganizationNextInvoice", "summary": "Get next invoice", - "description": "Returns the upcoming invoice for the next billing period for an organization. Returns null when no upcoming invoice is available.", + "description": "Returns the upcoming invoice for the next billing period for an organization. Returns null when no upcoming invoice is available.\n\nThis operation is only available in HCP Terraform.", "tags": [ "billing-invoices" ], @@ -963,13 +1093,22 @@ "content": { "application/json": { "schema": { - "type": "object", - "nullable": true, - "properties": { - "data": { - "$ref": "#/components/schemas/billing-invoices" + "oneOf": [ + { + "type": "string", + "enum": [ + "null" + ] + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/billing-invoices" + } + } } - } + ] } } } @@ -1418,100 +1557,35 @@ } } }, - "/organizations": { + "/cidr-range-lists/{cidr_range_list_id}": { + "x-vis": [ + "public-beta" + ], "get": { - "operationId": "listOrganizations", - "summary": "List Organizations", - "description": "List organizations.", + "operationId": "getCidrRangeList", + "summary": "Get CIDR Range List details", + "description": "Get details about a CIDR Range List\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "organizations" + "ip-allowlists" ], "parameters": [ { - "in": "query", - "name": "include", - "schema": { - "type": "string", - "enum": [ - "subscription" - ] - }, - "required": false, - "description": "Optionally side-load relationships of the specified name" - }, - { - "in": "query", - "name": "q", - "schema": { - "type": "string" - }, - "required": false, - "description": "A search query string. Organizations are searchable by name and notification email." - }, - { - "in": "query", - "name": "q[email]", - "schema": { - "type": "string" - }, - "required": false, - "description": "A search query string. This query searches organizations by notification email." - }, - { - "in": "query", - "name": "q[name]", + "in": "path", + "name": "cidr_range_list_id", "schema": { "type": "string" }, - "required": false, - "description": "A search query string. This query searches organizations by name." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "required": true, + "description": "CIDR Range List ID" } ], "responses": { "200": { - "description": "Organizations list", + "description": "CIDR Range List details", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/organizations" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "included": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/subscriptions" - } - ] - } - } - } + "$ref": "#/components/schemas/cidr-range-list-envelope" } } } @@ -1528,30 +1602,41 @@ } } }, - "post": { - "operationId": "createOrganization", - "summary": "Create Organization", - "description": "Create an organization.", + "patch": { + "operationId": "updateCidrRangeList", + "summary": "Update CIDR Range List", + "description": "Update a CIDR Range List\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "organizations" + "ip-allowlists" + ], + "parameters": [ + { + "in": "path", + "name": "cidr_range_list_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "CIDR Range List ID" + } ], "requestBody": { "required": true, "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/organizations-envelope" + "$ref": "#/components/schemas/cidr-range-list-envelope" } } } }, "responses": { - "201": { - "description": "Organization created", + "200": { + "description": "CIDR Range List updated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/organizations-envelope" + "$ref": "#/components/schemas/cidr-range-list-envelope" } } } @@ -1567,71 +1652,102 @@ } } } - } - }, - "/organizations/{organization_name}": { - "get": { - "operationId": "getOrganization", - "summary": "Get Organization details", - "description": "Get details about an organization.", + }, + "delete": { + "operationId": "deleteCidrRangeList", + "summary": "Delete CIDR Range List", + "description": "Delete a CIDR Range List.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "organizations" + "ip-allowlists" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "cidr_range_list_id", "schema": { "type": "string" }, "required": true, - "description": "Organization Name" - }, - { - "in": "query", - "name": "include", - "schema": { - "type": "string", - "enum": [ - "subscription" - ] - }, - "required": false, - "description": "Optionally side-load relationships of the specified name" + "description": "CIDR Range List ID" } ], "responses": { - "200": { - "description": "Organization details", + "204": { + "description": "CIDR Range List deleted" + }, + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/organizations-envelope" + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/cidr-range-lists/{cidr_range_list_id}/relationships/cidr-ranges": { + "x-vis": [ + "public-beta" + ], + "get": { + "operationId": "listCidrRanges", + "summary": "List CIDR Ranges", + "description": "List all CIDR Ranges in a CIDR Range List\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", + "tags": [ + "ip-allowlists" + ], + "parameters": [ + { + "in": "path", + "name": "cidr_range_list_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "CIDR Range List ID" + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/cidr-ranges" + } }, - { + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { "type": "object", "properties": { - "included": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/subscriptions" - } - ] - } + "pagination": { + "$ref": "#/components/schemas/pagination" } } } - ] + } } } } }, "default": { - "description": "Error details", + "description": "Organization not found, or user unauthorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -1642,22 +1758,22 @@ } } }, - "put": { + "post": { + "operationId": "createCidrRange", + "summary": "Create CIDR Range", + "description": "Create a new CIDR Range\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "organizations" + "ip-allowlists" ], - "operationId": "updateOrganization", - "summary": "Update Organization", - "description": "Update an organization.", "parameters": [ { "in": "path", - "name": "organization_name", + "name": "cidr_range_list_id", "schema": { "type": "string" }, "required": true, - "description": "Organization Name" + "description": "ID of a CIDR Range List for the newly created CIDR Range" } ], "requestBody": { @@ -1665,18 +1781,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/organizations-envelope" + "$ref": "#/components/schemas/cidr-ranges-envelope" } } } }, "responses": { - "200": { - "description": "Organization updated", + "201": { + "description": "CIDR Range created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/organizations-envelope" + "$ref": "#/components/schemas/cidr-ranges-envelope" } } } @@ -1692,23 +1808,28 @@ } } } - }, - "patch": { + } + }, + "/cidr-range-lists/{cidr_range_list_id}/relationships/agent-pools": { + "x-vis": [ + "public-beta" + ], + "post": { + "operationId": "assignAgentPoolsToCidrRangeList", + "summary": "Assign Agent Pools to a CIDR Range List", + "description": "Assign one or more Agent Pools to a CIDR Range List\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "organizations" + "ip-allowlists" ], - "operationId": "updateOrganization", - "summary": "Update Organization", - "description": "Update an organization.", "parameters": [ { "in": "path", - "name": "organization_name", + "name": "cidr_range_list_id", "schema": { "type": "string" }, "required": true, - "description": "Organization Name" + "description": "ID of a CIDR Range List to assign Agent Pools to" } ], "requestBody": { @@ -1716,21 +1837,14 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/organizations-envelope" + "$ref": "#/components/schemas/agent-pool-ids" } } } }, "responses": { - "200": { - "description": "Organization updated", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/organizations-envelope" - } - } - } + "204": { + "description": "Agent Pools assigned. No content is returned." }, "default": { "description": "Error details", @@ -1745,26 +1859,36 @@ } }, "delete": { - "operationId": "deleteOrganization", - "summary": "Delete Organization", - "description": "Delete an organization.", + "operationId": "unassignAgentPoolsFromCidrRangeList", + "summary": "Unassign Agent Pools from a CIDR Range List", + "description": "Unassign one or more Agent Pools from a CIDR Range List\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "organizations" + "ip-allowlists" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "cidr_range_list_id", "schema": { "type": "string" }, "required": true, - "description": "Organization Name" + "description": "ID of the CIDR Range List you want to unassign Agent Pools from" } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/agent-pool-ids" + } + } + } + }, "responses": { "204": { - "description": "Organization deleted" + "description": "Agent Pools unassigned. No content is returned." }, "default": { "description": "Error details", @@ -1779,142 +1903,35 @@ } } }, - "/organizations/{organization_name}/organization-memberships": { + "/cidr-ranges/{cidr_range_id}": { + "x-vis": [ + "public-beta" + ], "get": { - "operationId": "listOrganizationMemberships", - "summary": "List Organization Memberships", - "description": "List all memberships in an organization. This includes active/inactive members and invited users who have not yet accepted their invitation.", + "operationId": "getCidrRange", + "summary": "Get CIDR Range details", + "description": "Get details about a CIDR Range\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "organization-memberships" + "ip-allowlists" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "cidr_range_id", "schema": { "type": "string" }, "required": true, - "description": "The name of the organization to list memberships for" - }, - { - "in": "query", - "name": "q", - "schema": { - "type": "string" - }, - "required": false, - "description": "A search query string. Memberships are searchable by user name or email (case-insensitive)." - }, - { - "in": "query", - "name": "filter[status]", - "schema": { - "type": "string", - "enum": [ - "active", - "invited", - "inactive" - ] - }, - "required": false, - "description": "Filter memberships by status. Can be \"active\", \"invited\", or \"inactive\"." - }, - { - "in": "query", - "name": "filter[email]", - "schema": { - "type": "string", - "format": "email" - }, - "required": false, - "description": "Filter memberships by exact email address match." - }, - { - "in": "query", - "name": "include", - "schema": { - "type": "string", - "enum": [ - "user", - "teams" - ] - }, - "required": false, - "description": "Optionally side-load relationships. Can include \"user\" or \"teams\"." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "CIDR Range ID" } ], "responses": { "200": { - "description": "Organization memberships list", - "content": { - "application/vnd.api+json": { - "schema": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/organization-memberships" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "included": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/users" - }, - { - "$ref": "#/components/schemas/teams" - }, - { - "$ref": "#/components/schemas/organizations" - } - ] - } - } - } - } - } - } - }, - "400": { - "description": "Invalid filter or include parameter", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "404": { - "description": "Organization not found, or user unauthorized to perform action", + "description": "CIDR Range details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/cidr-ranges-envelope" } } } @@ -1931,22 +1948,22 @@ } } }, - "post": { - "operationId": "createOrganizationMembership", - "summary": "Invite a User to an Organization", - "description": "Invite a user to join an organization. Users can be invited by email address.", + "patch": { + "operationId": "updateCidrRange", + "summary": "Update CIDR Range", + "description": "Update a CIDR Range\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "organization-memberships" + "ip-allowlists" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "cidr_range_id", "schema": { "type": "string" }, "required": true, - "description": "The name of the organization the user will be invited to join" + "description": "CIDR Range ID" } ], "requestBody": { @@ -1954,71 +1971,24 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/organization-memberships-envelope" - }, - "examples": { - "inviteUser": { - "summary": "Invite a user to an organization with team memberships", - "value": { - "data": { - "type": "organization-memberships", - "attributes": { - "email": "user@example.com" - }, - "relationships": { - "teams": { - "data": [ - { - "type": "teams", - "id": "team-GeLZkdnK6xAVjA5H" - }, - { - "type": "teams", - "id": "team-XxEoUFzP9pW3r5d1" - } - ] - } - } - } - } - } + "$ref": "#/components/schemas/cidr-ranges-envelope" } } } }, "responses": { - "201": { - "description": "Successfully invited the user", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/organization-memberships-envelope" - } - } - } - }, - "400": { - "description": "Unable to invite user due to organization limits", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "404": { - "description": "Organization not found, or user unauthorized to perform action", + "200": { + "description": "CIDR Range updated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/cidr-ranges-envelope" } } } }, - "422": { - "description": "Unable to invite user due to validation errors (e.g., invalid email, missing teams)", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -2026,6 +1996,30 @@ } } } + } + } + }, + "delete": { + "operationId": "deleteCidrRange", + "summary": "Delete CIDR Range", + "description": "Delete a CIDR Range.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", + "tags": [ + "ip-allowlists" + ], + "parameters": [ + { + "in": "path", + "name": "cidr_range_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "CIDR Range ID" + } + ], + "responses": { + "204": { + "description": "CIDR Range deleted" }, "default": { "description": "Error details", @@ -2040,39 +2034,31 @@ } } }, - "/organization-memberships": { + "/organizations/{organization_name}/metrics-tokens": { + "x-vis": [ + "hcpt" + ], "get": { - "operationId": "listUserOrganizationMemberships", - "summary": "List User's Own Organization Memberships", - "description": "List all organization memberships for the currently authenticated user.", + "operationId": "listMetricsTokens", + "summary": "List tokens", + "description": "Lists all Metrics service tokens for the organization.\n\nThis operation is only available in HCP Terraform.", "tags": [ - "organization-memberships" + "metrics-tokens" ], "parameters": [ { - "in": "query", - "name": "include", + "in": "path", + "name": "organization_name", "schema": { - "type": "string", - "enum": [ - "user", - "teams", - "organization" - ] + "type": "string" }, - "required": false, - "description": "Optionally side-load relationships. Can include \"user\", \"teams\", or \"organization\"." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "required": true, + "description": "The name of the organization to list tokens for." } ], "responses": { "200": { - "description": "User's organization memberships list", + "description": "Success", "content": { "application/vnd.api+json": { "schema": { @@ -2084,34 +2070,7 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/organization-memberships" - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "included": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/users" - }, - { - "$ref": "#/components/schemas/teams" - }, - { - "$ref": "#/components/schemas/organizations" - } - ] + "$ref": "#/components/schemas/metrics-token" } } } @@ -2130,79 +2089,87 @@ } } } - } - }, - "/organization-memberships/{organization_membership_id}": { - "get": { - "operationId": "getOrganizationMembership", - "summary": "Show Organization Membership", - "description": "Get details about a specific organization membership.", + }, + "post": { + "operationId": "createMetricsToken", + "summary": "Generate a new token", + "description": "Generates a new Metrics Service token.\n\nThis operation is only available in HCP Terraform.", "tags": [ - "organization-memberships" + "metrics-tokens" ], "parameters": [ { "in": "path", - "name": "organization_membership_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The organization membership ID" - }, - { - "in": "query", - "name": "include", - "schema": { - "type": "string", - "enum": [ - "user", - "teams" - ] - }, - "required": false, - "description": "Optionally side-load relationships. Can include \"user\" or \"teams\"." + "description": "The name of the organization to generate a token for." } ], - "responses": { - "200": { - "description": "Organization membership details", - "content": { - "application/vnd.api+json": { - "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/organization-memberships-envelope" - }, - { - "type": "object", - "properties": { - "included": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/users" - }, - { - "$ref": "#/components/schemas/teams" - } - ] + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "metrics-tokens" + ] + }, + "attributes": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the token." + }, + "expires-at": { + "type": "string", + "format": "date-time", + "description": "The time when the token expires." } } } } - ] + } } } } - }, - "404": { - "description": "Organization membership not found, or user unauthorized to perform action", + } + }, + "responses": { + "201": { + "description": "Success", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/metrics-token" + } + } } } } @@ -2218,51 +2185,45 @@ } } } - }, + } + }, + "/organizations/{organization_name}/metrics-tokens/{id}": { + "x-vis": [ + "hcpt" + ], "delete": { - "operationId": "deleteOrganizationMembership", - "summary": "Remove User from Organization", - "description": "Remove a user from an organization. You cannot remove yourself from organizations which you own.", + "operationId": "deleteMetricsToken", + "summary": "Delete a token", + "description": "Deletes a Metrics Service token.\n\nThis operation is only available in HCP Terraform.", "tags": [ - "organization-memberships" + "metrics-tokens" ], "parameters": [ { "in": "path", - "name": "organization_membership_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The organization membership ID" + "description": "Which organization's token should be deleted." + }, + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the token to delete." } ], "responses": { "204": { - "description": "Successfully removed the user from the organization" + "description": "Success" }, - "403": { - "description": "Unable to remove the user. You cannot remove yourself from organizations which you own.", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "404": { - "description": "Organization membership not found, or user unauthorized to perform action", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "default": { - "description": "Error details", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -2274,98 +2235,53 @@ } } }, - "/organizations/{organization_name}/recoverable-items": { - "x-vis": [ - "public-beta" - ], + "/organizations": { "get": { - "operationId": "listRecoverableItems", - "summary": "List Recoverable Items", - "description": "List all recoverable items (soft-deleted resources) in an organization.", + "operationId": "listOrganizations", + "summary": "List Organizations", + "description": "List organizations.", "tags": [ - "recoverable-items" + "organizations" ], "parameters": [ - { - "in": "path", - "name": "organization_name", - "schema": { - "type": "string" - }, - "required": true, - "description": "The name of the organization." - }, { "in": "query", "name": "include", "schema": { "type": "string", "enum": [ - "recoverable", - "deleted_by", - "project" + "subscription" ] }, "required": false, - "description": "Optionally side-load relationships of the specified name. Multiple values can be comma-separated." + "description": "Optionally side-load relationships of the specified name" }, { "in": "query", - "name": "filter[search]", + "name": "q", "schema": { "type": "string" }, "required": false, - "description": "Search term to filter recoverable items by name or project name." - }, - { - "in": "query", - "name": "filter[having_managed_resources]", - "schema": { - "type": "boolean" - }, - "required": false, - "description": "If true, filter recoverable items that have managed resources. False has no effect." - }, - { - "in": "query", - "name": "filter[expires_after]", - "schema": { - "type": "string", - "format": "date-time" - }, - "required": false, - "description": "Filter recoverable items that expire after the specified date and time." + "description": "A search query string. Organizations are searchable by name and notification email." }, { "in": "query", - "name": "filter[recoverable_type]", + "name": "q[email]", "schema": { - "type": "string", - "enum": [ - "workspaces", - "stacks" - ] + "type": "string" }, "required": false, - "description": "Filter recoverable items by recoverable type." + "description": "A search query string. This query searches organizations by notification email." }, { "in": "query", - "name": "sort", + "name": "q[name]", "schema": { - "type": "string", - "enum": [ - "expires_at", - "-expires_at", - "recoverable_name", - "-recoverable_name", - "unmanaged_resources", - "-unmanaged_resources" - ] + "type": "string" }, "required": false, - "description": "Sort recoverable items by specified field. Prefix with '-' for descending order." + "description": "A search query string. This query searches organizations by name." }, { "$ref": "#/components/parameters/page_number" @@ -2376,31 +2292,49 @@ ], "responses": { "200": { - "description": "List of recoverable items", + "description": "Organizations list", "content": { "application/vnd.api+json": { "schema": { "type": "object", + "required": [ + "data" + ], "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/recoverable-items" + "$ref": "#/components/schemas/organizations" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } } }, "links": { "$ref": "#/components/schemas/self-with-pagination" }, - "meta": { - "$ref": "#/components/schemas/pagination" + "included": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/subscriptions" + } + ] + } } } } } } }, - "404": { - "description": "Organization not found or not entitled to this feature", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -2408,6 +2342,36 @@ } } } + } + } + }, + "post": { + "operationId": "createOrganization", + "summary": "Create Organization", + "description": "Create an organization.", + "tags": [ + "organizations" + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/organizations-envelope" + } + } + } + }, + "responses": { + "201": { + "description": "Organization created", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/organizations-envelope" + } + } + } }, "default": { "description": "Error details", @@ -2422,88 +2386,71 @@ } } }, - "/recoverable-items/{id}/actions/recover": { - "x-vis": [ - "public-beta" - ], - "put": { - "operationId": "recoverRecoverableItem", - "summary": "Recover a Recoverable Item", - "description": "Recover a soft-deleted resource by restoring it from a recoverable item. The resource must not be expired, permanently deleted, or already recovered.", + "/organizations/{organization_name}": { + "get": { + "operationId": "getOrganization", + "summary": "Get Organization details", + "description": "Get details about an organization.", "tags": [ - "recoverable-items" + "organizations" ], "parameters": [ { "in": "path", - "name": "id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "ID of the recoverable item." + "description": "Organization Name" + }, + { + "in": "query", + "name": "include", + "schema": { + "type": "string", + "enum": [ + "subscription", + "entitlement_set", + "default-project" + ] + }, + "required": false, + "description": "Optionally side-load relationships of the specified name" } ], "responses": { - "204": { - "description": "Successfully recovered the item. No content returned." - }, - "422": { - "description": "Recoverable item cannot be recovered due to its current state", + "200": { + "description": "Organization details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" - }, - "examples": { - "expired": { - "summary": "Item has expired", - "value": { - "errors": [ - { - "status": "422", - "title": "unprocessable content", - "detail": "Recoverable item has expired and is no longer eligible for recovery" - } - ] - } - }, - "permanently_deleted": { - "summary": "Item has been permanently deleted", - "value": { - "errors": [ - { - "status": "422", - "title": "unprocessable content", - "detail": "Recoverable item has been manually permanently deleted, and is no longer eligible for recovery" - } - ] - } - }, - "already_recovered": { - "summary": "Item has already been recovered", - "value": { - "errors": [ - { - "status": "422", - "title": "unprocessable content", - "detail": "Recoverable item has already been recovered" - } - ] - } - }, - "recovery_failed": { - "summary": "Recovery operation failed", - "value": { - "errors": [ - { - "status": "422", - "title": "unprocessable content", - "detail": "Recovery failed" + "allOf": [ + { + "$ref": "#/components/schemas/organizations-envelope" + }, + { + "type": "object", + "properties": { + "included": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/subscriptions" + }, + { + "$ref": "#/components/schemas/projects" + }, + { + "$ref": "#/components/schemas/entitlement-sets" + } + ] + } } - ] + } } - } + ] } } } @@ -2519,78 +2466,42 @@ } } } - } - }, - "/recoverable-items/{id}/actions/permanently-delete": { - "x-vis": [ - "public-beta" - ], + }, "put": { - "operationId": "permanentlyDeleteRecoverableItem", - "summary": "Permanently Delete a Recoverable Item", - "description": "Permanently delete a recoverable item, making the soft-deleted resource unrecoverable. The item must not be expired, already permanently deleted, or recovered.", "tags": [ - "recoverable-items" + "organizations" ], + "operationId": "updateOrganization", + "summary": "Update Organization", + "description": "Update an organization.", "parameters": [ { "in": "path", - "name": "id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "ID of the recoverable item." + "description": "Organization Name" } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/organizations-envelope" + } + } + } + }, "responses": { - "204": { - "description": "Successfully permanently deleted the item. No content returned." - }, - "422": { - "description": "Recoverable item cannot be permanently deleted due to its current state", + "200": { + "description": "Organization updated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" - }, - "examples": { - "already_expired": { - "summary": "Item has already expired", - "value": { - "errors": [ - { - "status": "422", - "title": "unprocessable content", - "detail": "Recoverable item has already expired and been permanently deleted" - } - ] - } - }, - "already_permanently_deleted": { - "summary": "Item has already been permanently deleted", - "value": { - "errors": [ - { - "status": "422", - "title": "unprocessable content", - "detail": "Recoverable item has already been manually permanently deleted" - } - ] - } - }, - "already_recovered": { - "summary": "Item has been recovered", - "value": { - "errors": [ - { - "status": "422", - "title": "unprocessable content", - "detail": "Recoverable item has been recovered, and is no longer eligible for permanent deletion" - } - ] - } - } + "$ref": "#/components/schemas/organizations-envelope" } } } @@ -2606,16 +2517,14 @@ } } } - } - }, - "/organizations/{organization_name}/projects": { - "get": { - "operationId": "listProjects", - "summary": "List Projects", - "description": "List all projects in an organization.", + }, + "patch": { "tags": [ - "projects" + "organizations" ], + "operationId": "updateOrganization", + "summary": "Update Organization", + "description": "Update an organization.", "parameters": [ { "in": "path", @@ -2624,72 +2533,26 @@ "type": "string" }, "required": true, - "description": "The name of the organization." - }, - { - "in": "query", - "name": "filter[names]", - "schema": { - "type": "string" - }, - "required": false, - "description": "Comma-separated list of project names to filter by." - }, - { - "in": "query", - "name": "filter[permissions][create-workspace]", - "schema": { - "type": "boolean" - }, - "required": false, - "description": "If present, returns a list of projects that the authenticated user can create workspaces in." - }, - { - "in": "query", - "name": "filter[permissions][update]", - "schema": { - "type": "boolean" - }, - "required": false, - "description": "If present, returns a list of projects that the authenticated user can update." - }, - { - "in": "query", - "name": "sort", - "schema": { - "type": "string" - }, - "required": false, - "description": "Optional. Allows sorting the organization's projects by \"name\". Prepending a hyphen to the sort parameter reverses the order. For example, \"-name\" sorts by name in reverse alphabetical order. If omitted, the default sort order is arbitrary but stable.\n" - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "Organization Name" } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/organizations-envelope" + } + } + } + }, "responses": { "200": { - "description": "List of projects", + "description": "Organization updated", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/projects" - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "meta": { - "$ref": "#/components/schemas/pagination" - } - } + "$ref": "#/components/schemas/organizations-envelope" } } } @@ -2706,12 +2569,12 @@ } } }, - "post": { - "operationId": "createProject", - "summary": "Create a Project", - "description": "Create a new project in an organization.", + "delete": { + "operationId": "deleteOrganization", + "summary": "Delete Organization", + "description": "Delete an organization.", "tags": [ - "projects" + "organizations" ], "parameters": [ { @@ -2721,29 +2584,12 @@ "type": "string" }, "required": true, - "description": "The name of the organization." + "description": "Organization Name" } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/projects-envelope" - } - } - } - }, "responses": { - "201": { - "description": "Project created", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/projects-envelope" - } - } - } + "204": { + "description": "Organization deleted" }, "default": { "description": "Error details", @@ -2758,13 +2604,16 @@ } } }, - "/organizations/{organization_name}/token-ttl-policies": { + "/organizations/{organization_name}/cidr-range-lists": { + "x-vis": [ + "public-beta" + ], "get": { - "operationId": "listTokenTtlPolicies", - "summary": "List Token TTL Policies", - "description": "List all token TTL policies for an organization.", + "operationId": "listCidrRangeLists", + "summary": "List CIDR Range Lists", + "description": "List all CIDR Range Lists in an organization\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "token-ttl-policies" + "ip-allowlists" ], "parameters": [ { @@ -2774,24 +2623,38 @@ "type": "string" }, "required": true, - "description": "The name of the organization to list token TTL policies for" + "description": "The name of the organization" + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" } ], "responses": { "200": { - "description": "Token TTL policies list", + "description": "Success", "content": { "application/vnd.api+json": { "schema": { "type": "object", - "required": [ - "data" - ], "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/token-ttl-policy" + "$ref": "#/components/schemas/cidr-range-lists" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } } } } @@ -2799,28 +2662,8 @@ } } }, - "403": { - "description": "User is not part of the owners team of the organization", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "404": { - "description": "Organization does not exist or user does not belong to the organization", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, "default": { - "description": "Error details", + "description": "Organization not found, or user unauthorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -2831,12 +2674,12 @@ } } }, - "patch": { - "operationId": "upsertTokenTtlPolicies", - "summary": "Create or Update Token TTL Policies", - "description": "Create or Update token TTL policies for an organization.", + "post": { + "operationId": "createCidrRangeList", + "summary": "Create CIDR Range List", + "description": "Create a new CIDR Range List\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "token-ttl-policies" + "ip-allowlists" ], "parameters": [ { @@ -2846,7 +2689,7 @@ "type": "string" }, "required": true, - "description": "The name of the organization" + "description": "Name of the organization" } ], "requestBody": { @@ -2854,81 +2697,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/token-ttl-policies-envelope" - }, - "examples": { - "upsert": { - "summary": "Upsert token TTL policies", - "value": { - "data": { - "type": "organization-token-ttl-policies", - "attributes": { - "token-ttl-policies": [ - { - "token-type": "organization", - "max-ttl-ms": 5184000000 - }, - { - "token-type": "user", - "max-ttl-ms": 189216000000 - } - ] - } - } - } - } + "$ref": "#/components/schemas/cidr-range-list-with-ranges-envelope" } } } }, "responses": { - "200": { - "description": "Successfully created or updated token TTL policies", - "content": { - "application/vnd.api+json": { - "schema": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/token-ttl-policy" - } - } - } - } - } - } - }, - "403": { - "description": "User is not part of the owners team of the organization", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "404": { - "description": "Organization does not exist or user does not belong to the organization", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "422": { - "description": "Unable to create token TTL policy due to validation errors", + "201": { + "description": "CIDR Range List created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/cidr-range-list-envelope" } } } @@ -2946,32 +2726,146 @@ } } }, - "/projects/{project_id}": { + "/organizations/{organization_name}/organization-memberships": { "get": { - "operationId": "getProject", - "summary": "Get Project", - "description": "Get details of a specific project.", + "operationId": "listOrganizationMemberships", + "summary": "List Organization Memberships", + "description": "List all memberships in an organization. This includes active/inactive members and invited users who have not yet accepted their invitation.", "tags": [ - "projects" + "organization-memberships" ], "parameters": [ { "in": "path", - "name": "project_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the project." + "description": "The name of the organization to list memberships for" + }, + { + "in": "query", + "name": "q", + "schema": { + "type": "string" + }, + "required": false, + "description": "A search query string. Memberships are searchable by user name or email (case-insensitive)." + }, + { + "in": "query", + "name": "filter[status]", + "schema": { + "type": "string", + "enum": [ + "active", + "invited", + "inactive" + ] + }, + "required": false, + "description": "Filter memberships by status. Can be \"active\", \"invited\", or \"inactive\"." + }, + { + "in": "query", + "name": "filter[email]", + "schema": { + "type": "string", + "format": "email" + }, + "required": false, + "description": "Filter memberships by exact email address match." + }, + { + "in": "query", + "name": "include", + "schema": { + "type": "string", + "enum": [ + "user", + "teams", + "scim-identity" + ] + }, + "required": false, + "description": "Optionally side-load relationships. Can include \"user\", \"teams\", or \"scim-identity\".\nNote: \"scim-identity\" is only available on HCP Terraform.\n" + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" } ], "responses": { "200": { - "description": "Project details", + "description": "Organization memberships list", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/projects-envelope" + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/organization-memberships" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "included": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/users" + }, + { + "$ref": "#/components/schemas/teams" + }, + { + "$ref": "#/components/schemas/organizations" + }, + { + "$ref": "#/components/schemas/scim-identities" + } + ] + } + } + } + } + } + } + }, + "400": { + "description": "Invalid filter or include parameter", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "404": { + "description": "Organization not found, or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -2988,22 +2882,22 @@ } } }, - "patch": { - "operationId": "updateProject", - "summary": "Update Project", - "description": "Update an existing project.", + "post": { + "operationId": "createOrganizationMembership", + "summary": "Invite a User to an Organization", + "description": "Invite a user to join an organization. Users can be invited by email address.", "tags": [ - "projects" + "organization-memberships" ], "parameters": [ { "in": "path", - "name": "project_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the project." + "description": "The name of the organization the user will be invited to join" } ], "requestBody": { @@ -3011,24 +2905,51 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/projects-envelope" + "$ref": "#/components/schemas/organization-memberships-envelope" + }, + "examples": { + "inviteUser": { + "summary": "Invite a user to an organization with team memberships", + "value": { + "data": { + "type": "organization-memberships", + "attributes": { + "email": "user@example.com" + }, + "relationships": { + "teams": { + "data": [ + { + "type": "teams", + "id": "team-GeLZkdnK6xAVjA5H" + }, + { + "type": "teams", + "id": "team-XxEoUFzP9pW3r5d1" + } + ] + } + } + } + } + } } } } }, "responses": { - "200": { - "description": "Project updated", + "201": { + "description": "Successfully invited the user", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/projects-envelope" + "$ref": "#/components/schemas/organization-memberships-envelope" } } } }, - "default": { - "description": "Error details", + "400": { + "description": "Unable to invite user due to organization limits", "content": { "application/vnd.api+json": { "schema": { @@ -3036,33 +2957,9 @@ } } } - } - } - }, - "delete": { - "operationId": "deleteProject", - "summary": "Delete Project", - "description": "Delete a project.", - "tags": [ - "projects" - ], - "parameters": [ - { - "in": "path", - "name": "project_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the project." - } - ], - "responses": { - "204": { - "description": "Project deleted" }, - "default": { - "description": "Error details", + "404": { + "description": "Organization not found, or user unauthorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -3070,42 +2967,16 @@ } } } - } - } - } - }, - "/projects/{project_id}/relationships/workspaces": { - "post": { - "operationId": "moveWorkspacesIntoProject", - "summary": "Move Workspaces into a Project", - "description": "Move one or more workspaces into a project. You must have permission to move workspaces on the destination project as well as any source project(s). If you are not authorized to move any of the workspaces in the request, or if any workspaces in the request are not found, then no workspaces will be moved.\n", - "tags": [ - "projects" - ], - "parameters": [ - { - "in": "path", - "name": "project_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the destination project." - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-identifier-array-document" + }, + "422": { + "description": "Unable to invite user due to validation errors (e.g., invalid email, missing teams)", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } } } - } - }, - "responses": { - "204": { - "description": "Successfully moved workspace(s)." }, "default": { "description": "Error details", @@ -3120,42 +2991,81 @@ } } }, - "/projects/{project_id}/relationships/tag-bindings": { + "/organization-memberships": { "get": { - "operationId": "listProjectTagBindings", - "summary": "List Project Tag Bindings", - "description": "List all tags associated with a project.", + "operationId": "listUserOrganizationMemberships", + "summary": "List User's Own Organization Memberships", + "description": "List all organization memberships for the currently authenticated user.", "tags": [ - "projects" + "organization-memberships" ], "parameters": [ { - "in": "path", - "name": "project_id", + "in": "query", + "name": "include", "schema": { - "type": "string" + "type": "string", + "enum": [ + "user", + "teams", + "organization" + ] }, - "required": true, - "description": "The ID of the project." + "required": false, + "description": "Optionally side-load relationships. Can include \"user\", \"teams\", or \"organization\"." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" } ], "responses": { "200": { - "description": "List of tags", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/tag-bindings-collection" - } - } - } - }, - "404": { - "description": "Project not found or user unauthorized to view project", + "description": "User's organization memberships list", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/organization-memberships" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "included": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/users" + }, + { + "$ref": "#/components/schemas/teams" + }, + { + "$ref": "#/components/schemas/organizations" + } + ] + } + } + } } } } @@ -3171,41 +3081,75 @@ } } } - }, - "post": { - "operationId": "addProjectTagBindings", - "summary": "Add Tag Bindings to a Project", - "description": "Add one or more tag bindings to a project.", + } + }, + "/organization-memberships/{organization_membership_id}": { + "get": { + "operationId": "getOrganizationMembership", + "summary": "Show Organization Membership", + "description": "Get details about a specific organization membership.", "tags": [ - "projects" + "organization-memberships" ], "parameters": [ { "in": "path", - "name": "project_id", + "name": "organization_membership_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the project." + "description": "The organization membership ID" + }, + { + "in": "query", + "name": "include", + "schema": { + "type": "string", + "enum": [ + "user", + "teams" + ] + }, + "required": false, + "description": "Optionally side-load relationships. Can include \"user\" or \"teams\"." } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/tag-bindings-collection" + "responses": { + "200": { + "description": "Organization membership details", + "content": { + "application/vnd.api+json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/organization-memberships-envelope" + }, + { + "type": "object", + "properties": { + "included": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/users" + }, + { + "$ref": "#/components/schemas/teams" + } + ] + } + } + } + } + ] + } } } - } - }, - "responses": { - "204": { - "description": "Tags added" }, "404": { - "description": "Project not found or user unauthorized to manage tags", + "description": "Organization membership not found, or user unauthorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -3226,40 +3170,40 @@ } } }, - "patch": { - "operationId": "replaceProjectTagBindings", - "summary": "Replace Tag Bindings in a Project", - "description": "Replace all tag bindings in a project.", + "delete": { + "operationId": "deleteOrganizationMembership", + "summary": "Remove User from Organization", + "description": "Remove a user from an organization. You cannot remove yourself from organizations which you own.", "tags": [ - "projects" + "organization-memberships" ], "parameters": [ { "in": "path", - "name": "project_id", + "name": "organization_membership_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the project." + "description": "The organization membership ID" } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/tag-bindings-collection" - } - } - } - }, "responses": { "204": { - "description": "Tag bindings replaced" + "description": "Successfully removed the user from the organization" + }, + "403": { + "description": "Unable to remove the user. You cannot remove yourself from organizations which you own.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } }, "404": { - "description": "Project not found or user unauthorized to manage tag bindings", + "description": "Organization membership not found, or user unauthorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -3281,13 +3225,16 @@ } } }, - "/organizations/{organization_name}/workspaces": { + "/organizations/{organization_name}/recoverable-items": { + "x-vis": [ + "public-beta" + ], "get": { - "operationId": "listWorkspaces", - "summary": "List Workspaces", - "description": "List all workspaces in an organization.", + "operationId": "listRecoverableItems", + "summary": "List Recoverable Items", + "description": "List all recoverable items (soft-deleted resources) in an organization.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "recoverable-items" ], "parameters": [ { @@ -3301,95 +3248,75 @@ }, { "in": "query", - "name": "search[name]", - "schema": { - "type": "string" - }, - "required": false, - "description": "Partial name to filter workspaces by name." - }, - { - "in": "query", - "name": "search[wildcard-name]", - "schema": { - "type": "string" - }, - "required": false, - "description": "Wildcard name filter for workspaces." - }, - { - "in": "query", - "name": "filter[current-run][status]", - "schema": { - "type": "string" - }, - "required": false, - "description": "Comma-separated list of run statuses to filter workspaces by." - }, - { - "in": "query", - "name": "filter[project][id]", + "name": "include", "schema": { - "type": "string" + "type": "string", + "enum": [ + "recoverable", + "deleted_by", + "project" + ] }, "required": false, - "description": "Filter workspaces by project external ID." + "description": "Optionally side-load relationships of the specified name. Multiple values can be comma-separated." }, { "in": "query", - "name": "filter[tagged]", + "name": "filter[search]", "schema": { "type": "string" }, "required": false, - "description": "Filter workspaces by tag names." + "description": "Search term to filter recoverable items by name or project name." }, { "in": "query", - "name": "filter[tagged][value]", + "name": "filter[having_managed_resources]", "schema": { - "type": "string" + "type": "boolean" }, "required": false, - "description": "Filter workspaces by tag key=value pairs." + "description": "If true, filter recoverable items that have managed resources. False has no effect." }, { "in": "query", - "name": "filter[tag-union]", + "name": "filter[expires_after]", "schema": { - "type": "boolean", - "default": false + "type": "string", + "format": "date-time" }, "required": false, - "description": "Use OR logic for filter[tagged] across effective tag bindings when any provided tag key/value pair may match. By default, filtering uses intersection semantics, so all provided tags must match." + "description": "Filter recoverable items that expire after the specified date and time." }, { "in": "query", - "name": "filter[tag-value-default-null]", + "name": "filter[recoverable_type]", "schema": { - "type": "boolean", - "default": false + "type": "string", + "enum": [ + "workspaces", + "stacks" + ] }, "required": false, - "description": "Treat omitted filter[tagged][value] fields as NULL for effective tag bindings." + "description": "Filter recoverable items by recoverable type." }, { "in": "query", "name": "sort", "schema": { - "type": "string" - }, - "required": false, - "description": "Sort workspaces. Valid values include name, current-run.created-at. Prefix with a hyphen (e.g., -name) to sort in descending order.\n" - }, - { - "in": "query", - "name": "include", - "schema": { - "type": "string" + "type": "string", + "enum": [ + "expires_at", + "-expires_at", + "recoverable_name", + "-recoverable_name", + "unmanaged_resources", + "-unmanaged_resources" + ] }, "required": false, - "description": "Comma-separated list of relationship names to side-load (e.g., current_run, readme, effective_tag_bindings).\n" + "description": "Sort recoverable items by specified field. Prefix with '-' for descending order." }, { "$ref": "#/components/parameters/page_number" @@ -3400,43 +3327,23 @@ ], "responses": { "200": { - "description": "List of workspaces", + "description": "List of recoverable items", "content": { "application/vnd.api+json": { "schema": { "type": "object", - "required": [ - "data" - ], "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/workspaces" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - }, - "status-counts": { - "type": "object", - "additionalProperties": { - "type": "integer" - } - } + "$ref": "#/components/schemas/recoverable-items" } }, "links": { "$ref": "#/components/schemas/self-with-pagination" }, - "included": { - "type": "array", - "items": { - "type": "object" - } + "meta": { + "$ref": "#/components/schemas/pagination" } } } @@ -3444,7 +3351,7 @@ } }, "404": { - "description": "Organization not found or user unauthorized to view workspaces", + "description": "Organization not found or not entitled to this feature", "content": { "application/vnd.api+json": { "schema": { @@ -3464,62 +3371,90 @@ } } } - }, - "post": { - "operationId": "createWorkspace", - "summary": "Create a Workspace", - "description": "Create a new workspace in an organization.", + } + }, + "/recoverable-items/{id}/actions/recover": { + "x-vis": [ + "public-beta" + ], + "put": { + "operationId": "recoverRecoverableItem", + "summary": "Recover a Recoverable Item", + "description": "Recover a soft-deleted resource by restoring it from a recoverable item. The resource must not be expired, permanently deleted, or already recovered.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "recoverable-items" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "id", "schema": { "type": "string" }, "required": true, - "description": "The name of the organization." + "description": "ID of the recoverable item." } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-envelope" - } - } - } - }, "responses": { - "201": { - "description": "Workspace created", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-envelope" - } - } - } - }, - "404": { - "description": "Organization not found or user unauthorized to create workspaces", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } + "204": { + "description": "Successfully recovered the item. No content returned." }, "422": { - "description": "Malformed request body or validation error", + "description": "Recoverable item cannot be recovered due to its current state", "content": { "application/vnd.api+json": { "schema": { "$ref": "#/components/schemas/errors" + }, + "examples": { + "expired": { + "summary": "Item has expired", + "value": { + "errors": [ + { + "status": "422", + "title": "unprocessable content", + "detail": "Recoverable item has expired and is no longer eligible for recovery" + } + ] + } + }, + "permanently_deleted": { + "summary": "Item has been permanently deleted", + "value": { + "errors": [ + { + "status": "422", + "title": "unprocessable content", + "detail": "Recoverable item has been manually permanently deleted, and is no longer eligible for recovery" + } + ] + } + }, + "already_recovered": { + "summary": "Item has already been recovered", + "value": { + "errors": [ + { + "status": "422", + "title": "unprocessable content", + "detail": "Recoverable item has already been recovered" + } + ] + } + }, + "recovery_failed": { + "summary": "Recovery operation failed", + "value": { + "errors": [ + { + "status": "422", + "title": "unprocessable content", + "detail": "Recovery failed" + } + ] + } + } } } } @@ -3537,71 +3472,156 @@ } } }, - "/organizations/{organization_name}/workspaces/{workspace_name}": { - "get": { - "operationId": "getWorkspaceByName", - "summary": "Get a Workspace by Name", - "description": "Get details of a workspace by organization name and workspace name.", + "/recoverable-items/{id}/actions/permanently-delete": { + "x-vis": [ + "public-beta" + ], + "put": { + "operationId": "permanentlyDeleteRecoverableItem", + "summary": "Permanently Delete a Recoverable Item", + "description": "Permanently delete a recoverable item, making the soft-deleted resource unrecoverable. The item must not be expired, already permanently deleted, or recovered.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "recoverable-items" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "id", "schema": { "type": "string" }, "required": true, - "description": "The name of the organization." + "description": "ID of the recoverable item." + } + ], + "responses": { + "204": { + "description": "Successfully permanently deleted the item. No content returned." }, + "422": { + "description": "Recoverable item cannot be permanently deleted due to its current state", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + }, + "examples": { + "already_expired": { + "summary": "Item has already expired", + "value": { + "errors": [ + { + "status": "422", + "title": "unprocessable content", + "detail": "Recoverable item has already expired and been permanently deleted" + } + ] + } + }, + "already_permanently_deleted": { + "summary": "Item has already been permanently deleted", + "value": { + "errors": [ + { + "status": "422", + "title": "unprocessable content", + "detail": "Recoverable item has already been manually permanently deleted" + } + ] + } + }, + "already_recovered": { + "summary": "Item has been recovered", + "value": { + "errors": [ + { + "status": "422", + "title": "unprocessable content", + "detail": "Recoverable item has been recovered, and is no longer eligible for permanent deletion" + } + ] + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/organizations/{organization_name}/relationships/module-producers": { + "x-vis": [ + "tfe" + ], + "get": { + "operationId": "listModuleProducers", + "summary": "List Module Producers", + "description": "List organizations that are configured to share modules with an organization.\n\nThis operation is only available in Terraform Enterprise.", + "tags": [ + "organizations" + ], + "parameters": [ { "in": "path", - "name": "workspace_name", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The name of the workspace." + "description": "The name of the organization's module producers to view." }, { - "in": "query", - "name": "include", - "schema": { - "type": "string" - }, - "required": false, - "description": "Optionally side-load relationships. Comma-separated list of relationship names (e.g. current_run, current_state_version, locked_by, outputs, project, agent_pool).\n" + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" } ], "responses": { "200": { - "description": "Workspace details", + "description": "Module producers list", "content": { "application/vnd.api+json": { "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/workspaces-envelope" + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/organizations" + } }, - { + "meta": { "type": "object", "properties": { - "included": { - "type": "array", - "items": { - "type": "object" - } + "pagination": { + "$ref": "#/components/schemas/pagination" } } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" } - ] + } } } } }, - "404": { - "description": "Workspace not found or user unauthorized to view workspace", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -3609,6 +3629,43 @@ } } } + } + } + } + }, + "/organizations/{organization_name}/relationships/data-retention-policy": { + "x-vis": [ + "tfe" + ], + "get": { + "operationId": "getDataRetentionPolicy", + "summary": "Get Data Retention Policy", + "description": "Show the data retention policy set explicitly on the organization.\n\nThis operation is only available in Terraform Enterprise.", + "tags": [ + "organizations", + "data-retention-policies" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the organization to show the data retention policy for." + } + ], + "responses": { + "200": { + "description": "Data retention policy details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/data-retention-policy-envelope" + } + } + } }, "default": { "description": "Error details", @@ -3622,13 +3679,14 @@ } } }, - "patch": { - "operationId": "updateWorkspaceByName", - "summary": "Update a Workspace by Name", - "description": "Update settings of an existing workspace by organization name and workspace name.", + "post": { "tags": [ - "workspaces" + "organizations", + "data-retention-policies" ], + "operationId": "createOrUpdateDataRetentionPolicy", + "summary": "Create or Update Data Retention Policy", + "description": "Create a data retention policy for an organization or update the existing policy.\n\nThis operation is only available in Terraform Enterprise.", "parameters": [ { "in": "path", @@ -3637,16 +3695,7 @@ "type": "string" }, "required": true, - "description": "The name of the organization." - }, - { - "in": "path", - "name": "workspace_name", - "schema": { - "type": "string" - }, - "required": true, - "description": "The name of the workspace." + "description": "The name of the organization to update the data retention policy for." } ], "requestBody": { @@ -3654,24 +3703,17 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspaces-envelope" + "$ref": "#/components/schemas/data-retention-policy-envelope" } } } }, "responses": { - "200": { - "description": "Workspace updated", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-envelope" - } - } - } + "204": { + "description": "Data retention policy created or updated" }, - "404": { - "description": "Workspace not found or user unauthorized to view workspace", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -3679,16 +3721,41 @@ } } } - }, - "422": { - "description": "Malformed request body", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } + } + } + }, + "patch": { + "tags": [ + "organizations", + "data-retention-policies" + ], + "operationId": "createOrUpdateDataRetentionPolicy", + "summary": "Create or Update Data Retention Policy", + "description": "Create a data retention policy for an organization or update the existing policy.\n\nThis operation is only available in Terraform Enterprise.", + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the organization to update the data retention policy for." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/data-retention-policy-envelope" } } + } + }, + "responses": { + "204": { + "description": "Data retention policy created or updated" }, "default": { "description": "Error details", @@ -3703,11 +3770,12 @@ } }, "delete": { - "operationId": "deleteWorkspaceByName", - "summary": "Delete a Workspace by Name", - "description": "Delete a workspace by organization name and workspace name. This permanently removes the workspace and all its associated data.\n", + "operationId": "deleteDataRetentionPolicy", + "summary": "Delete Data Retention Policy", + "description": "Remove the data retention policy explicitly set on an organization.\n\nThis operation is only available in Terraform Enterprise.", "tags": [ - "workspaces" + "organizations", + "data-retention-policies" ], "parameters": [ { @@ -3717,31 +3785,12 @@ "type": "string" }, "required": true, - "description": "The name of the organization." - }, - { - "in": "path", - "name": "workspace_name", - "schema": { - "type": "string" - }, - "required": true, - "description": "The name of the workspace." + "description": "The name of the organization to remove the data retention policy for." } ], "responses": { "204": { - "description": "Workspace deleted" - }, - "404": { - "description": "Workspace not found or user unauthorized to delete workspace", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } + "description": "Data retention policy deleted" }, "default": { "description": "Error details", @@ -3756,13 +3805,13 @@ } } }, - "/organizations/{organization_name}/workspaces/{workspace_name}/actions/safe-delete": { - "post": { - "operationId": "safeDeleteWorkspaceByName", - "summary": "Safe Delete a Workspace by Name", - "description": "Delete a workspace by organization name and workspace name only if it has no resources under management. Returns a conflict error if the workspace has managed resources or is locked.\n", + "/organizations/{organization_name}/projects": { + "get": { + "operationId": "listProjects", + "summary": "List Projects", + "description": "List all projects in an organization.", "tags": [ - "workspaces" + "projects" ], "parameters": [ { @@ -3775,160 +3824,40 @@ "description": "The name of the organization." }, { - "in": "path", - "name": "workspace_name", + "in": "query", + "name": "filter[names]", "schema": { "type": "string" }, - "required": true, - "description": "The name of the workspace." - } - ], - "responses": { - "204": { - "description": "Workspace deleted" + "required": false, + "description": "Comma-separated list of project names to filter by." }, - "404": { - "description": "Workspace not found or user unauthorized to delete workspace", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "409": { - "description": "Workspace has managed resources or is locked and cannot be safely deleted", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "default": { - "description": "Error details", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - } - } - } - }, - "/projects/{project_id}/notification-configurations": { - "get": { - "summary": "List Notification Configurations for a Project", - "description": "List all notification configurations for a given project.\n", - "operationId": "listProjectNotificationConfigurations", - "tags": [ - "Notification Configurations" - ], - "parameters": [ { - "name": "project_id", - "in": "path", - "description": "The ID of the project", - "required": true, + "in": "query", + "name": "filter[permissions][create-workspace]", "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/notification-configurations" - } - } - } - } - } - } + "type": "boolean" + }, + "required": false, + "description": "If present, returns a list of projects that the authenticated user can create workspaces in." }, - "404": { - "description": "Project not found" - } - } - }, - "post": { - "summary": "Create a Notification Configuration for a Project", - "description": "Create a new notification configuration for a given project.\n", - "operationId": "createProjectNotificationConfiguration", - "tags": [ - "Notification Configurations" - ], - "parameters": [ { - "name": "project_id", - "in": "path", - "description": "The ID of the project", - "required": true, + "in": "query", + "name": "filter[permissions][update]", "schema": { - "type": "string" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/notification-configurations-envelope" - } - } - } - }, - "responses": { - "201": { - "description": "Notification configuration created successfully", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/notification-configurations-envelope" - } - } - } - }, - "404": { - "description": "Project not found" + "type": "boolean" + }, + "required": false, + "description": "If present, returns a list of projects that the authenticated user can update." }, - "422": { - "description": "Validation error" - } - } - } - }, - "/workspaces/{workspace_id}/notification-configurations": { - "get": { - "operationId": "listWorkspaceNotificationConfigurations", - "summary": "List Notification Configurations for a Workspace", - "description": "List all notification configurations for a workspace.", - "tags": [ - "notification-configurations" - ], - "parameters": [ { - "in": "path", - "name": "workspace_id", + "in": "query", + "name": "sort", "schema": { "type": "string" }, - "required": true, - "description": "The ID of the workspace." + "required": false, + "description": "Optional. Allows sorting the organization's projects by \"name\". Prepending a hyphen to the sort parameter reverses the order. For example, \"-name\" sorts by name in reverse alphabetical order. If omitted, the default sort order is arbitrary but stable.\n" }, { "$ref": "#/components/parameters/page_number" @@ -3939,7 +3868,7 @@ ], "responses": { "200": { - "description": "List of notification configurations", + "description": "List of projects", "content": { "application/vnd.api+json": { "schema": { @@ -3948,19 +3877,14 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/notification-configurations" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } + "$ref": "#/components/schemas/projects" } }, "links": { "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "$ref": "#/components/schemas/pagination" } } } @@ -3980,21 +3904,21 @@ } }, "post": { - "operationId": "createWorkspaceNotificationConfiguration", - "summary": "Create a Notification Configuration for a Workspace", - "description": "Create a new notification configuration for a workspace.", + "operationId": "createProject", + "summary": "Create a Project", + "description": "Create a new project in an organization.", "tags": [ - "notification-configurations" + "projects" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the workspace." + "description": "The name of the organization." } ], "requestBody": { @@ -4002,18 +3926,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/notification-configurations-envelope" + "$ref": "#/components/schemas/projects-envelope" } } } }, "responses": { "201": { - "description": "Notification configuration created", + "description": "Project created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/notification-configurations-envelope" + "$ref": "#/components/schemas/projects-envelope" } } } @@ -4031,61 +3955,67 @@ } } }, - "/teams/{team_id}/notification-configurations": { + "/organizations/{organization_name}/token-ttl-policies": { "get": { - "operationId": "listTeamNotificationConfigurations", - "summary": "List Notification Configurations for a Team", - "description": "List all notification configurations for a team.", + "operationId": "listTokenTtlPolicies", + "summary": "List Token TTL Policies", + "description": "List all token TTL policies for an organization.", "tags": [ - "notification-configurations" + "token-ttl-policies" ], "parameters": [ { "in": "path", - "name": "team_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the team." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "The name of the organization to list token TTL policies for" } ], "responses": { "200": { - "description": "List of notification configurations", + "description": "Token TTL policies list", "content": { "application/vnd.api+json": { "schema": { "type": "object", + "required": [ + "data" + ], "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/notification-configurations" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } + "$ref": "#/components/schemas/token-ttl-policy" } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" } } } } } }, + "403": { + "description": "User is not part of the owners team of the organization", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "404": { + "description": "Organization does not exist or user does not belong to the organization", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, "default": { "description": "Error details", "content": { @@ -4098,22 +4028,22 @@ } } }, - "post": { - "operationId": "createTeamNotificationConfiguration", - "summary": "Create a Notification Configuration for a Team", - "description": "Create a new notification configuration for a team.", + "patch": { + "operationId": "upsertTokenTtlPolicies", + "summary": "Create or Update Token TTL Policies", + "description": "Create or Update token TTL policies for an organization.", "tags": [ - "notification-configurations" + "token-ttl-policies" ], "parameters": [ { "in": "path", - "name": "team_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the team." + "description": "The name of the organization" } ], "requestBody": { @@ -4121,18 +4051,81 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/notification-configurations-envelope" - } - } - } - }, - "responses": { - "201": { - "description": "Notification configuration created", + "$ref": "#/components/schemas/token-ttl-policies-envelope" + }, + "examples": { + "upsert": { + "summary": "Upsert token TTL policies", + "value": { + "data": { + "type": "organization-token-ttl-policies", + "attributes": { + "token-ttl-policies": [ + { + "token-type": "organization", + "max-ttl-ms": 5184000000 + }, + { + "token-type": "user", + "max-ttl-ms": 189216000000 + } + ] + } + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Successfully created or updated token TTL policies", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/notification-configurations-envelope" + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/token-ttl-policy" + } + } + } + } + } + } + }, + "403": { + "description": "User is not part of the owners team of the organization", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "404": { + "description": "Organization does not exist or user does not belong to the organization", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Unable to create token TTL policy due to validation errors", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -4150,32 +4143,32 @@ } } }, - "/notification-configurations/{notification_configuration_id}": { + "/projects/{project_id}": { "get": { - "operationId": "getNotificationConfiguration", - "summary": "Show a Notification Configuration", - "description": "Get details about a notification configuration.", + "operationId": "getProject", + "summary": "Get Project", + "description": "Get details of a specific project.", "tags": [ - "notification-configurations" + "projects" ], "parameters": [ { "in": "path", - "name": "notification_configuration_id", + "name": "project_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the notification configuration." + "description": "The ID of the project." } ], "responses": { "200": { - "description": "Notification configuration details", + "description": "Project details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/notification-configurations-envelope" + "$ref": "#/components/schemas/projects-envelope" } } } @@ -4193,21 +4186,21 @@ } }, "patch": { - "operationId": "updateNotificationConfiguration", - "summary": "Update a Notification Configuration", - "description": "Update an existing notification configuration.", + "operationId": "updateProject", + "summary": "Update Project", + "description": "Update an existing project.", "tags": [ - "notification-configurations" + "projects" ], "parameters": [ { "in": "path", - "name": "notification_configuration_id", + "name": "project_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the notification configuration." + "description": "The ID of the project." } ], "requestBody": { @@ -4215,18 +4208,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/notification-configurations-envelope" + "$ref": "#/components/schemas/projects-envelope" } } } }, "responses": { "200": { - "description": "Notification configuration updated", + "description": "Project updated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/notification-configurations-envelope" + "$ref": "#/components/schemas/projects-envelope" } } } @@ -4244,26 +4237,26 @@ } }, "delete": { - "operationId": "deleteNotificationConfiguration", - "summary": "Delete a Notification Configuration", - "description": "Delete a notification configuration.", + "operationId": "deleteProject", + "summary": "Delete Project", + "description": "Delete a project.", "tags": [ - "notification-configurations" + "projects" ], "parameters": [ { "in": "path", - "name": "notification_configuration_id", + "name": "project_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the notification configuration." + "description": "The ID of the project." } ], "responses": { "204": { - "description": "Notification configuration deleted" + "description": "Project deleted" }, "default": { "description": "Error details", @@ -4278,35 +4271,38 @@ } } }, - "/notification-configurations/{notification_configuration_id}/actions/enable": { + "/projects/{project_id}/relationships/workspaces": { "post": { - "operationId": "enableNotificationConfiguration", - "summary": "Enable a Notification Configuration", - "description": "Enable a notification configuration by triggering a verification request.", + "operationId": "moveWorkspacesIntoProject", + "summary": "Move Workspaces into a Project", + "description": "Move one or more workspaces into a project. You must have permission to move workspaces on the destination project as well as any source project(s). If you are not authorized to move any of the workspaces in the request, or if any workspaces in the request are not found, then no workspaces will be moved.\n", "tags": [ - "notification-configurations" + "projects" ], "parameters": [ { "in": "path", - "name": "notification_configuration_id", + "name": "project_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the notification configuration." + "description": "The ID of the destination project." } ], - "responses": { - "200": { - "description": "Notification configuration enabled", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/notification-configurations-envelope" - } + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspaces-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Successfully moved workspace(s)." }, "default": { "description": "Error details", @@ -4321,32 +4317,42 @@ } } }, - "/notification-configurations/{notification_configuration_id}/actions/verify": { - "post": { - "operationId": "verifyNotificationConfiguration", - "summary": "Verify a Notification Configuration", - "description": "Send a verification request to the configured destination URL.", + "/projects/{project_id}/relationships/tag-bindings": { + "get": { + "operationId": "listProjectTagBindings", + "summary": "List Project Tag Bindings", + "description": "List all tags associated with a project.", "tags": [ - "notification-configurations" + "projects" ], "parameters": [ { "in": "path", - "name": "notification_configuration_id", + "name": "project_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the notification configuration." + "description": "The ID of the project." } ], "responses": { "200": { - "description": "Notification configuration verified", + "description": "List of tags", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/notification-configurations-envelope" + "$ref": "#/components/schemas/tag-bindings-collection" + } + } + } + }, + "404": { + "description": "Project not found or user unauthorized to view project", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -4362,53 +4368,45 @@ } } } - } - }, - "/email-recipient-statuses/verify": { - "get": { - "operationId": "verifyEmailRecipientStatus", - "summary": "Verify Email Recipient", - "description": "Render the email verification page using a signed token. This endpoint is public and does not require authentication.", + }, + "post": { + "operationId": "addProjectTagBindings", + "summary": "Add Tag Bindings to a Project", + "description": "Add one or more tag bindings to a project.", "tags": [ - "email-recipient-statuses" + "projects" ], "parameters": [ { - "in": "query", - "name": "token", + "in": "path", + "name": "project_id", "schema": { "type": "string" }, "required": true, - "description": "The signed token for verifying the email address" - }, - { - "in": "query", - "name": "config", - "schema": { - "type": "string" - }, - "required": false, - "description": "The notification configuration external ID used to render the subscribable name" + "description": "The ID of the project." } ], - "responses": { - "200": { - "description": "Email verification page rendered successfully", - "content": { - "text/html": { - "schema": { - "type": "string" - } + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/tag-bindings-collection" } } + } + }, + "responses": { + "204": { + "description": "Tags added" }, "404": { - "description": "Invalid or expired token", + "description": "Project not found or user unauthorized to manage tags", "content": { - "text/html": { + "application/vnd.api+json": { "schema": { - "type": "string" + "$ref": "#/components/schemas/errors" } } } @@ -4416,68 +4414,49 @@ "default": { "description": "Error details", "content": { - "text/html": { + "application/vnd.api+json": { "schema": { - "type": "string" + "$ref": "#/components/schemas/errors" } } } } } }, - "post": { - "operationId": "performEmailRecipientVerification", - "summary": "Perform Email Recipient Verification", - "description": "Verify an email recipient status using a signed token. This endpoint is public and does not require authentication.", + "patch": { + "operationId": "replaceProjectTagBindings", + "summary": "Replace Tag Bindings in a Project", + "description": "Replace all tag bindings in a project.", "tags": [ - "email-recipient-statuses" + "projects" ], - "requestBody": { - "required": true, + "parameters": [ + { + "in": "path", + "name": "project_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the project." + } + ], + "requestBody": { + "required": true, "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "required": [ - "token" - ], - "properties": { - "token": { - "type": "string", - "description": "The signed token for verifying the email address" - }, - "config": { - "type": "string", - "description": "The notification configuration external ID used to render the subscribable name" - } - } + "$ref": "#/components/schemas/tag-bindings-collection" } } } }, "responses": { - "200": { - "description": "Email recipient verification completed successfully", - "content": { - "text/html": { - "schema": { - "type": "string" - } - } - } + "204": { + "description": "Tag bindings replaced" }, "404": { - "description": "Invalid or expired token", - "content": { - "text/html": { - "schema": { - "type": "string" - } - } - } - }, - "415": { - "description": "Invalid content type", + "description": "Project not found or user unauthorized to manage tag bindings", "content": { "application/vnd.api+json": { "schema": { @@ -4489,9 +4468,9 @@ "default": { "description": "Error details", "content": { - "text/html": { + "application/vnd.api+json": { "schema": { - "type": "string" + "$ref": "#/components/schemas/errors" } } } @@ -4499,79 +4478,115 @@ } } }, - "/email-recipient-statuses/unsubscribe": { + "/organizations/{organization_name}/workspaces": { "get": { - "operationId": "unsubscribeEmailRecipient", - "summary": "Unsubscribe Email Recipient", - "description": "Unsubscribe an email recipient from notifications using a signed token. This endpoint is public and does not require authentication.", + "operationId": "listWorkspaces", + "summary": "List Workspaces", + "description": "List all workspaces in an organization.", "tags": [ - "email-recipient-statuses" + "workspaces" ], "parameters": [ { - "in": "query", - "name": "token", + "in": "path", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The signed token for unsubscribing the email address" - } - ], - "responses": { - "200": { - "description": "Email recipient unsubscribed successfully", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/email-recipient-statuses-envelope" - } - } - } + "description": "The name of the organization." }, - "404": { - "description": "Invalid or expired token", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } + { + "in": "query", + "name": "search[name]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Partial name to filter workspaces by name." }, - "default": { - "description": "Error details", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - } - } - } - }, - "/workspaces/{workspace_id}/queries": { - "x-vs": [ - "internal-beta" - ], - "get": { - "operationId": "getWorkspaceQueries", - "summary": "Get Queries for a Workspace", - "description": "Get list of queries for a particular workspace.", - "tags": [ - "queries" - ], - "parameters": [ { - "in": "path", - "name": "workspace_id", + "in": "query", + "name": "search[wildcard-name]", "schema": { "type": "string" }, - "required": true, - "description": "The id of the workspace." + "required": false, + "description": "Wildcard name filter for workspaces." + }, + { + "in": "query", + "name": "filter[current-run][status]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Comma-separated list of run statuses to filter workspaces by." + }, + { + "in": "query", + "name": "filter[project][id]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Filter workspaces by project external ID." + }, + { + "in": "query", + "name": "filter[tagged]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Filter workspaces by tag names." + }, + { + "in": "query", + "name": "filter[tagged][value]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Filter workspaces by tag key=value pairs." + }, + { + "in": "query", + "name": "filter[tag-union]", + "schema": { + "type": "boolean", + "default": false + }, + "required": false, + "description": "Use OR logic for filter[tagged] across effective tag bindings when any provided tag key/value pair may match. By default, filtering uses intersection semantics, so all provided tags must match." + }, + { + "in": "query", + "name": "filter[tag-value-default-null]", + "schema": { + "type": "boolean", + "default": false + }, + "required": false, + "description": "Treat omitted filter[tagged][value] fields as NULL for effective tag bindings." + }, + { + "in": "query", + "name": "sort", + "schema": { + "type": "string" + }, + "required": false, + "description": "Sort workspaces. Valid values include name, current-run.created-at. Prefix with a hyphen (e.g., -name) to sort in descending order.\n" + }, + { + "in": "query", + "name": "include", + "schema": { + "type": "string" + }, + "required": false, + "description": "Comma-separated list of relationship names to side-load (e.g., current_run, readme, effective_tag_bindings).\n" }, { "$ref": "#/components/parameters/page_number" @@ -4582,29 +4597,59 @@ ], "responses": { "200": { - "description": "List of Queries", + "description": "List of workspaces", "content": { "application/vnd.api+json": { "schema": { "type": "object", + "required": [ + "data" + ], "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/queries" + "$ref": "#/components/schemas/workspaces" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + }, + "status-counts": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + } } }, "links": { "$ref": "#/components/schemas/self-with-pagination" }, - "meta": { - "$ref": "#/components/schemas/pagination" + "included": { + "type": "array", + "items": { + "type": "object" + } } } } } } }, + "404": { + "description": "Organization not found or user unauthorized to view workspaces", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, "default": { "description": "Error details", "content": { @@ -4616,45 +4661,62 @@ } } } - } - }, - "/workspaces/{workspace_id}/all-vars": { - "get": { - "operationId": "listAllVars", - "summary": "List All Variables Accessible to a Workspace", - "description": "This API returns the list of all variables that are accessible to a workspace. This includes variables defined directly on the workspace as well as variables inherited from any variable sets attached to the workspace.", - "tags": [ - "vars" - ], - "parameters": [ + }, + "post": { + "operationId": "createWorkspace", + "summary": "Create a Workspace", + "description": "Create a new workspace in an organization.", + "tags": [ + "workspaces" + ], + "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the workspace." + "description": "The name of the organization." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspaces-envelope" + } + } + } + }, "responses": { - "200": { - "description": "List of all variables accessible to a workspace", + "201": { + "description": "Workspace created", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/vars" - } - } - } + "$ref": "#/components/schemas/workspaces-envelope" + } + } + } + }, + "404": { + "description": "Organization not found or user unauthorized to create workspaces", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Malformed request body or validation error", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -4672,43 +4734,75 @@ } } }, - "/workspaces/{workspace_id}/vars": { + "/organizations/{organization_name}/workspaces/{workspace_name}": { "get": { - "operationId": "listWorkspaceVars", - "summary": "List Variables", - "description": "List variables for a workspace.", + "operationId": "getWorkspaceByName", + "summary": "Get a Workspace by Name", + "description": "Get details of a workspace by organization name and workspace name.", "tags": [ - "vars" + "workspaces" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the workspace." + "description": "The name of the organization." + }, + { + "in": "path", + "name": "workspace_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the workspace." + }, + { + "in": "query", + "name": "include", + "schema": { + "type": "string" + }, + "required": false, + "description": "Optionally side-load relationships. Comma-separated list of relationship names (e.g. current_run, current_state_version, locked_by, outputs, project, agent_pool).\n" } ], "responses": { "200": { - "description": "List of variables for the workspace", + "description": "Workspace details", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/vars" + "allOf": [ + { + "$ref": "#/components/schemas/workspaces-envelope" + }, + { + "type": "object", + "properties": { + "included": { + "type": "array", + "items": { + "type": "object" + } + } } } - } + ] + } + } + } + }, + "404": { + "description": "Workspace not found or user unauthorized to view workspace", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -4725,22 +4819,31 @@ } } }, - "post": { - "operationId": "createWorkspaceVar", - "summary": "Create a Variable", - "description": "Create a variable for a workspace.", + "patch": { + "operationId": "updateWorkspaceByName", + "summary": "Update a Workspace by Name", + "description": "Update settings of an existing workspace by organization name and workspace name.", "tags": [ - "vars" + "workspaces" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the workspace." + "description": "The name of the organization." + }, + { + "in": "path", + "name": "workspace_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the workspace." } ], "requestBody": { @@ -4748,18 +4851,38 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/workspaces-envelope" } } } }, "responses": { - "201": { - "description": "Variable created", + "200": { + "description": "Workspace updated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/workspaces-envelope" + } + } + } + }, + "404": { + "description": "Workspace not found or user unauthorized to view workspace", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Malformed request body", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -4775,43 +4898,44 @@ } } } - } - }, - "/workspaces/{workspace_id}/vars/{id}": { - "get": { - "operationId": "showWorkspaceVar", - "summary": "Show a Variable", - "description": "Show details of a variable in a workspace.", + }, + "delete": { + "operationId": "deleteWorkspaceByName", + "summary": "Delete a Workspace by Name", + "description": "Delete a workspace by organization name and workspace name. This permanently removes the workspace and all its associated data.\n", "tags": [ - "vars" + "workspaces" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the workspace." + "description": "The name of the organization." }, { "in": "path", - "name": "id", + "name": "workspace_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable." + "description": "The name of the workspace." } ], "responses": { - "200": { - "description": "Variable details", + "204": { + "description": "Workspace deleted" + }, + "404": { + "description": "Workspace not found or user unauthorized to delete workspace", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/errors" } } } @@ -4827,57 +4951,52 @@ } } } - }, - "patch": { - "operationId": "updateWorkspaceVar", - "summary": "Update a Variable", - "description": "Update attributes of an existing variable in a workspace.", + } + }, + "/organizations/{organization_name}/workspaces/{workspace_name}/actions/safe-delete": { + "post": { + "operationId": "safeDeleteWorkspaceByName", + "summary": "Safe Delete a Workspace by Name", + "description": "Delete a workspace by organization name and workspace name only if it has no resources under management. Returns a conflict error if the workspace has managed resources or is locked.\n", "tags": [ - "vars" + "workspaces" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the workspace." + "description": "The name of the organization." }, { "in": "path", - "name": "id", + "name": "workspace_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable." + "description": "The name of the workspace." } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/vars-envelope" - } - } - } - }, "responses": { - "200": { - "description": "Variable updated", + "204": { + "description": "Workspace deleted" + }, + "404": { + "description": "Workspace not found or user unauthorized to delete workspace", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/errors" } } } }, - "default": { - "description": "Error details", + "409": { + "description": "Workspace has managed resources or is locked and cannot be safely deleted", "content": { "application/vnd.api+json": { "schema": { @@ -4885,39 +5004,6 @@ } } } - } - } - }, - "delete": { - "operationId": "deleteWorkspaceVar", - "summary": "Delete a Variable", - "description": "Delete a variable from a workspace.", - "tags": [ - "vars" - ], - "parameters": [ - { - "in": "path", - "name": "workspace_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the workspace." - }, - { - "in": "path", - "name": "id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the variable." - } - ], - "responses": { - "204": { - "description": "Variable deleted successfully" }, "default": { "description": "Error details", @@ -4932,38 +5018,46 @@ } } }, - "/varsets/{varset_id}": { + "/projects/{project_id}/notification-configurations": { "get": { - "operationId": "showVarset", - "summary": "Show a Variable Set", - "description": "Fetch details about the specified variable set.", + "summary": "List Notification Configurations for a Project", + "description": "List all notification configurations for a given project.\n", + "operationId": "listProjectNotificationConfigurations", "tags": [ - "varsets" + "Notification Configurations" ], "parameters": [ { + "name": "project_id", "in": "path", - "name": "varset_id", + "description": "The ID of the project", + "required": true, "schema": { "type": "string" - }, - "required": true, - "description": "The ID of the variable set." + } } ], "responses": { "200": { - "description": "Variable set details", + "description": "Success", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/varsets-envelope" + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/notification-configurations" + } + } + } } } } }, - "default": { - "description": "Error details", + "404": { + "description": "Project not found", "content": { "application/vnd.api+json": { "schema": { @@ -4974,22 +5068,22 @@ } } }, - "patch": { - "operationId": "updateVarset", - "summary": "Update a Variable Set", - "description": "Update attributes of an existing variable set.", + "post": { + "summary": "Create a Notification Configuration for a Project", + "description": "Create a new notification configuration for a given project.\n", + "operationId": "createProjectNotificationConfiguration", "tags": [ - "varsets" + "Notification Configurations" ], "parameters": [ { + "name": "project_id", "in": "path", - "name": "varset_id", + "description": "The ID of the project", + "required": true, "schema": { "type": "string" - }, - "required": true, - "description": "The ID of the variable set." + } } ], "requestBody": { @@ -4997,24 +5091,24 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/varsets-envelope" + "$ref": "#/components/schemas/notification-configurations-envelope" } } } }, "responses": { - "200": { - "description": "Variable set updated", + "201": { + "description": "Notification configuration created successfully", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/varsets-envelope" + "$ref": "#/components/schemas/notification-configurations-envelope" } } } }, - "default": { - "description": "Error details", + "400": { + "description": "Bad request", "content": { "application/vnd.api+json": { "schema": { @@ -5022,50 +5116,9 @@ } } } - } - } - }, - "post": { - "operationId": "updateVarsetPost", - "summary": "Update a Variable Set (POST)", - "description": "Update attributes of an existing variable set using POST.", - "tags": [ - "varsets" - ], - "parameters": [ - { - "in": "path", - "name": "varset_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the variable set." - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/varsets-envelope" - } - } - } - }, - "responses": { - "200": { - "description": "Variable set updated", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/varsets-envelope" - } - } - } }, - "default": { - "description": "Error details", + "404": { + "description": "Project not found", "content": { "application/vnd.api+json": { "schema": { @@ -5073,33 +5126,9 @@ } } } - } - } - }, - "delete": { - "operationId": "deleteVarset", - "summary": "Delete a Variable Set", - "description": "Delete an existing variable set.", - "tags": [ - "varsets" - ], - "parameters": [ - { - "in": "path", - "name": "varset_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the variable set." - } - ], - "responses": { - "204": { - "description": "Variable set deleted successfully" }, - "default": { - "description": "Error details", + "422": { + "description": "Validation error", "content": { "application/vnd.api+json": { "schema": { @@ -5111,53 +5140,23 @@ } } }, - "/organizations/{organization_name}/varsets": { + "/workspaces/{workspace_id}/notification-configurations": { "get": { - "operationId": "listOrganizationVarsets", - "summary": "List Variable Sets for an Organization", - "description": "List all variable sets for an organization.", + "operationId": "listWorkspaceNotificationConfigurations", + "summary": "List Notification Configurations for a Workspace", + "description": "List all notification configurations for a workspace.", "tags": [ - "varsets" + "notification-configurations" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The name of the organization." - }, - { - "in": "query", - "name": "q", - "schema": { - "type": "string" - }, - "required": false, - "description": "A search query string. You can search for a variable set using its name." - }, - { - "in": "query", - "name": "filter[global]", - "schema": { - "type": "boolean" - }, - "required": false, - "description": "When true, returns only global variable sets. When false, returns only non-global variable sets." - }, - { - "in": "query", - "name": "scope", - "schema": { - "type": "string", - "enum": [ - "owned" - ] - }, - "required": false, - "description": "When set to \"owned\", returns only organization-owned variable sets." + "description": "The ID of the workspace." }, { "$ref": "#/components/parameters/page_number" @@ -5168,7 +5167,7 @@ ], "responses": { "200": { - "description": "List of variable sets for the organization", + "description": "List of notification configurations", "content": { "application/vnd.api+json": { "schema": { @@ -5177,14 +5176,19 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/varsets" + "$ref": "#/components/schemas/notification-configurations" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } } }, "links": { "$ref": "#/components/schemas/self-with-pagination" - }, - "meta": { - "$ref": "#/components/schemas/pagination" } } } @@ -5204,21 +5208,21 @@ } }, "post": { - "operationId": "createVarset", - "summary": "Create a Variable Set", - "description": "Create a new variable set in an organization.", + "operationId": "createWorkspaceNotificationConfiguration", + "summary": "Create a Notification Configuration for a Workspace", + "description": "Create a new notification configuration for a workspace.", "tags": [ - "varsets" + "notification-configurations" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The name of the organization." + "description": "The ID of the workspace." } ], "requestBody": { @@ -5226,18 +5230,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/varsets-envelope" + "$ref": "#/components/schemas/notification-configurations-envelope" } } } }, "responses": { "201": { - "description": "Variable set created", + "description": "Notification configuration created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/varsets-envelope" + "$ref": "#/components/schemas/notification-configurations-envelope" } } } @@ -5255,40 +5259,51 @@ } } }, - "/varsets/{varset_id}/relationships/vars": { + "/teams/{team_id}/notification-configurations": { "get": { - "operationId": "listVarsetVars", - "summary": "List Variables in a Variable Set", - "description": "List all variables in a variable set.", + "operationId": "listTeamNotificationConfigurations", + "summary": "List Notification Configurations for a Team", + "description": "List all notification configurations for a team.", "tags": [ - "varsets" + "notification-configurations" ], "parameters": [ { "in": "path", - "name": "varset_id", + "name": "team_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable set." + "description": "The ID of the team." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" } ], "responses": { "200": { - "description": "List of variables in the variable set", + "description": "List of notification configurations", "content": { "application/vnd.api+json": { "schema": { "type": "object", - "required": [ - "data" - ], "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/vars" + "$ref": "#/components/schemas/notification-configurations" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } } }, "links": { @@ -5312,21 +5327,21 @@ } }, "post": { - "operationId": "addVarsetVar", - "summary": "Add a Variable to a Variable Set", - "description": "Add a new variable to an existing variable set.", + "operationId": "createTeamNotificationConfiguration", + "summary": "Create a Notification Configuration for a Team", + "description": "Create a new notification configuration for a team.", "tags": [ - "varsets" + "notification-configurations" ], "parameters": [ { "in": "path", - "name": "varset_id", + "name": "team_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable set." + "description": "The ID of the team." } ], "requestBody": { @@ -5334,18 +5349,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/notification-configurations-envelope" } } } }, "responses": { "201": { - "description": "Variable added to variable set", + "description": "Notification configuration created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/notification-configurations-envelope" } } } @@ -5363,41 +5378,32 @@ } } }, - "/varsets/{varset_id}/relationships/vars/{id}": { + "/notification-configurations/{notification_configuration_id}": { "get": { - "operationId": "showVarsetVar", - "summary": "Show a Variable in a Variable Set", - "description": "Show details of a variable in a variable set.", + "operationId": "getNotificationConfiguration", + "summary": "Show a Notification Configuration", + "description": "Get details about a notification configuration.", "tags": [ - "varsets" + "notification-configurations" ], "parameters": [ { "in": "path", - "name": "varset_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the variable set." - }, - { - "in": "path", - "name": "id", + "name": "notification_configuration_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable." + "description": "The ID of the notification configuration." } ], "responses": { "200": { - "description": "Variable details", + "description": "Notification configuration details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/notification-configurations-envelope" } } } @@ -5415,30 +5421,21 @@ } }, "patch": { - "operationId": "updateVarsetVar", - "summary": "Update a Variable in a Variable Set", - "description": "Update attributes of an existing variable in a variable set.", + "operationId": "updateNotificationConfiguration", + "summary": "Update a Notification Configuration", + "description": "Update an existing notification configuration.", "tags": [ - "varsets" + "notification-configurations" ], "parameters": [ { "in": "path", - "name": "varset_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the variable set." - }, - { - "in": "path", - "name": "id", + "name": "notification_configuration_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable to update." + "description": "The ID of the notification configuration." } ], "requestBody": { @@ -5446,18 +5443,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/notification-configurations-envelope" } } } }, "responses": { "200": { - "description": "Variable updated", + "description": "Notification configuration updated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/notification-configurations-envelope" } } } @@ -5475,35 +5472,26 @@ } }, "delete": { - "operationId": "deleteVarsetVar", - "summary": "Delete a Variable from a Variable Set", - "description": "Delete a variable from a variable set.", + "operationId": "deleteNotificationConfiguration", + "summary": "Delete a Notification Configuration", + "description": "Delete a notification configuration.", "tags": [ - "varsets" + "notification-configurations" ], "parameters": [ { "in": "path", - "name": "varset_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the variable set." - }, - { - "in": "path", - "name": "id", + "name": "notification_configuration_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable to delete." + "description": "The ID of the notification configuration." } ], "responses": { "204": { - "description": "Variable deleted successfully" + "description": "Notification configuration deleted" }, "default": { "description": "Error details", @@ -5518,50 +5506,32 @@ } } }, - "/workspaces/{workspace_id}/varsets/{varset_id}/relationships/vars/{id}": { - "get": { - "operationId": "showWorkspaceVarsetVar", - "summary": "Show a Variable in a Variable Set (Workspace Context)", - "description": "Show details of a variable in a variable set, with overwrite context from the specified workspace.", + "/notification-configurations/{notification_configuration_id}/actions/enable": { + "post": { + "operationId": "enableNotificationConfiguration", + "summary": "Enable a Notification Configuration", + "description": "Enable a notification configuration by triggering a verification request.", "tags": [ - "varsets" + "notification-configurations" ], "parameters": [ { "in": "path", - "name": "workspace_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the workspace providing overwrite context." - }, - { - "in": "path", - "name": "varset_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the variable set." - }, - { - "in": "path", - "name": "id", + "name": "notification_configuration_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable." + "description": "The ID of the notification configuration." } ], "responses": { "200": { - "description": "Variable details with workspace overwrite context", + "description": "Notification configuration enabled", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/notification-configurations-envelope" } } } @@ -5579,55 +5549,32 @@ } } }, - "/workspaces/{workspace_id}/varsets/{varset_id}/relationships/vars": { - "get": { - "operationId": "listWorkspaceVarsetVars", - "summary": "List Variables in a Variable Set (Workspace Context)", - "description": "List all variables in a variable set, with overwrite context from the specified workspace.", + "/notification-configurations/{notification_configuration_id}/actions/verify": { + "post": { + "operationId": "verifyNotificationConfiguration", + "summary": "Verify a Notification Configuration", + "description": "Send a verification request to the configured destination URL.", "tags": [ - "varsets" + "notification-configurations" ], "parameters": [ { "in": "path", - "name": "workspace_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the workspace providing overwrite context." - }, - { - "in": "path", - "name": "varset_id", + "name": "notification_configuration_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable set." + "description": "The ID of the notification configuration." } ], "responses": { "200": { - "description": "List of variables in the variable set with workspace overwrite context", + "description": "Notification configuration verified", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/vars" - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } + "$ref": "#/components/schemas/notification-configurations-envelope" } } } @@ -5645,85 +5592,120 @@ } } }, - "/varsets/{varset_id}/relationships/projects": { - "post": { - "operationId": "applyVarsetToProjects", - "summary": "Apply Variable Set to Projects", - "description": "Apply a variable set to one or more projects. When you apply a variable set to a project, all the workspaces in that project will have the variable set applied to them.", + "/email-recipient-statuses/verify": { + "get": { + "operationId": "verifyEmailRecipientStatus", + "summary": "Verify Email Recipient", + "description": "Render the email verification page using a signed token. This endpoint is public and does not require authentication.", "tags": [ - "varsets" + "email-recipient-statuses" ], "parameters": [ { - "in": "path", - "name": "varset_id", + "in": "query", + "name": "token", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable set." + "description": "The signed token for verifying the email address" + }, + { + "in": "query", + "name": "config", + "schema": { + "type": "string" + }, + "required": false, + "description": "The notification configuration external ID used to render the subscribable name" } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/projects-identifier-array-document" + "responses": { + "200": { + "description": "Email verification page rendered successfully", + "content": { + "text/html": { + "schema": { + "type": "string" + } } } - } - }, - "responses": { - "204": { - "description": "Variable set successfully applied to the requested projects." }, - "default": { - "description": "Error details", + "404": { + "description": "Invalid or expired token", "content": { - "application/vnd.api+json": { + "text/html": { "schema": { - "$ref": "#/components/schemas/errors" + "type": "string" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "text/html": { + "schema": { + "type": "string" } } } } - } - }, - "delete": { - "operationId": "removeVarsetFromProjects", - "summary": "Remove Variable Set from Projects", - "description": "Remove a variable set from one or more projects.", - "tags": [ - "varsets" - ], - "parameters": [ - { - "in": "path", - "name": "varset_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the variable set." - } + } + }, + "post": { + "operationId": "performEmailRecipientVerification", + "summary": "Perform Email Recipient Verification", + "description": "Verify an email recipient status using a signed token. This endpoint is public and does not require authentication.", + "tags": [ + "email-recipient-statuses" ], "requestBody": { "required": true, "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/projects-identifier-array-document" + "type": "object", + "required": [ + "token" + ], + "properties": { + "token": { + "type": "string", + "description": "The signed token for verifying the email address" + }, + "config": { + "type": "string", + "description": "The notification configuration external ID used to render the subscribable name" + } + } } } } }, "responses": { - "204": { - "description": "Variable set successfully removed from the requested projects." + "200": { + "description": "Email recipient verification completed successfully", + "content": { + "text/html": { + "schema": { + "type": "string" + } + } + } }, - "default": { - "description": "Error details", + "404": { + "description": "Invalid or expired token", + "content": { + "text/html": { + "schema": { + "type": "string" + } + } + } + }, + "415": { + "description": "Invalid content type", "content": { "application/vnd.api+json": { "schema": { @@ -5731,42 +5713,59 @@ } } } + }, + "default": { + "description": "Error details", + "content": { + "text/html": { + "schema": { + "type": "string" + } + } + } } } } }, - "/varsets/{varset_id}/relationships/workspaces": { - "post": { - "operationId": "applyVarsetToWorkspaces", - "summary": "Apply Variable Set to Workspaces", - "description": "Apply a variable set to one or more workspaces.", + "/email-recipient-statuses/unsubscribe": { + "get": { + "operationId": "unsubscribeEmailRecipient", + "summary": "Unsubscribe Email Recipient", + "description": "Unsubscribe an email recipient from notifications using a signed token. This endpoint is public and does not require authentication.", "tags": [ - "varsets" + "email-recipient-statuses" ], "parameters": [ { - "in": "path", - "name": "varset_id", + "in": "query", + "name": "token", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable set." + "description": "The signed token for unsubscribing the email address" } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-identifier-array-document" + "responses": { + "200": { + "description": "Email recipient unsubscribed successfully", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/email-recipient-statuses-envelope" + } + } + } + }, + "404": { + "description": "Invalid or expired token", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } } } - } - }, - "responses": { - "204": { - "description": "Variable set successfully applied to the requested workspaces." }, "default": { "description": "Error details", @@ -5780,44 +5779,79 @@ } } }, - "delete": { - "operationId": "removeVarsetFromWorkspaces", - "summary": "Remove Variable Set from Workspaces", - "description": "Remove a variable set from one or more workspaces.", + "post": { + "operationId": "saveUnsubscribePreferences", + "summary": "Save Email Unsubscribe Preferences", + "description": "Save email unsubscribe preferences using a signed token. This endpoint is public and does not require authentication.", "tags": [ - "varsets" + "email-recipient-statuses" ], "parameters": [ { - "in": "path", - "name": "varset_id", + "in": "query", + "name": "token", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable set." + "description": "The signed token for the unsubscribe operation" } ], "requestBody": { "required": true, "content": { - "application/vnd.api+json": { + "application/x-www-form-urlencoded": { "schema": { - "$ref": "#/components/schemas/workspaces-identifier-array-document" + "type": "object", + "properties": { + "unsubscribe_preference": { + "type": "string", + "enum": [ + "project", + "all_organization", + "cancel" + ], + "description": "The unsubscribe preference selected by the user" + }, + "configuration": { + "type": "string", + "description": "Optional external ID of the notification configuration (for project unsubscribe)" + } + }, + "required": [ + "unsubscribe_preference" + ] } } } }, "responses": { - "204": { - "description": "Variable set successfully removed from the requested workspaces." + "200": { + "description": "Preferences saved successfully", + "content": { + "text/html": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Invalid or expired token", + "content": { + "text/html": { + "schema": { + "type": "string" + } + } + } }, "default": { "description": "Error details", "content": { - "application/vnd.api+json": { + "text/html": { "schema": { - "$ref": "#/components/schemas/errors" + "type": "string" } } } @@ -5825,38 +5859,58 @@ } } }, - "/varsets/{varset_id}/relationships/stacks": { - "post": { - "operationId": "applyVarsetToStacks", - "summary": "Apply Variable Set to Stacks", - "description": "Apply a variable set to one or more Stacks. Only available in HCP Terraform.", + "/workspaces/{workspace_id}/queries": { + "x-vs": [ + "internal-beta" + ], + "get": { + "operationId": "getWorkspaceQueries", + "summary": "Get Queries for a Workspace", + "description": "Get list of queries for a particular workspace.", "tags": [ - "varsets" + "queries" ], "parameters": [ { "in": "path", - "name": "varset_id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable set." + "description": "The id of the workspace." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/jsonapi-identifier-array-document" + "responses": { + "200": { + "description": "List of Queries", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/queries" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "$ref": "#/components/schemas/pagination" + } + } + } } } - } - }, - "responses": { - "204": { - "description": "Variable set successfully applied to the requested Stacks." }, "default": { "description": "Error details", @@ -5869,38 +5923,48 @@ } } } - }, - "delete": { - "operationId": "removeVarsetFromStacks", - "summary": "Remove Variable Set from Stacks", - "description": "Remove a variable set from one or more Stacks.", + } + }, + "/workspaces/{workspace_id}/all-vars": { + "get": { + "operationId": "listAllVars", + "summary": "List All Variables Accessible to a Workspace", + "description": "This API returns the list of all variables that are accessible to a workspace. This includes variables defined directly on the workspace as well as variables inherited from any variable sets attached to the workspace.", "tags": [ - "varsets" + "vars" ], "parameters": [ { "in": "path", - "name": "varset_id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the variable set." + "description": "The ID of the workspace." } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/jsonapi-identifier-array-document" + "responses": { + "200": { + "description": "List of all variables accessible to a workspace", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/vars" + } + } + } + } } } - } - }, - "responses": { - "204": { - "description": "Variable set successfully removed from the requested Stacks." }, "default": { "description": "Error details", @@ -5915,74 +5979,41 @@ } } }, - "/projects/{project_id}/varsets": { + "/workspaces/{workspace_id}/vars": { "get": { - "operationId": "listProjectVarsets", - "summary": "List Variable Sets for a Project", - "description": "List all variable sets for a project. This includes global variable sets from the project's organization.", + "operationId": "listWorkspaceVars", + "summary": "List Variables", + "description": "List variables for a workspace.", "tags": [ - "varsets" + "vars" ], "parameters": [ { "in": "path", - "name": "project_id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the project." - }, - { - "in": "query", - "name": "q", - "schema": { - "type": "string" - }, - "required": false, - "description": "A search query string. You can search for a variable set using its name." - }, - { - "in": "query", - "name": "scope", - "schema": { - "type": "string", - "enum": [ - "applied", - "shared", - "owned", - "all" - ] - }, - "required": false, - "description": "Filter variable sets by scope relative to the project." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "The ID of the workspace." } ], "responses": { "200": { - "description": "List of variable sets for the project", + "description": "List of variables for the workspace", "content": { "application/vnd.api+json": { "schema": { "type": "object", + "required": [ + "data" + ], "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/varsets" + "$ref": "#/components/schemas/vars" } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "meta": { - "$ref": "#/components/schemas/pagination" } } } @@ -6000,15 +6031,13 @@ } } } - } - }, - "/workspaces/{workspace_id}/varsets": { - "get": { - "operationId": "listWorkspaceVarsets", - "summary": "List Variable Sets for a Workspace", - "description": "List all variable sets for a workspace. This includes global variable sets from the workspace's organization and variable sets attached to the project this workspace is contained within.", + }, + "post": { + "operationId": "createWorkspaceVar", + "summary": "Create a Variable", + "description": "Create a variable for a workspace.", "tags": [ - "varsets" + "vars" ], "parameters": [ { @@ -6019,44 +6048,25 @@ }, "required": true, "description": "The ID of the workspace." - }, - { - "in": "query", - "name": "q", - "schema": { - "type": "string" - }, - "required": false, - "description": "A search query string. You can search for a variable set using its name." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/vars-envelope" + } + } + } + }, "responses": { - "200": { - "description": "List of variable sets for the workspace", + "201": { + "description": "Variable created", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/varsets" - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "meta": { - "$ref": "#/components/schemas/pagination" - } - } + "$ref": "#/components/schemas/vars-envelope" } } } @@ -6074,13 +6084,13 @@ } } }, - "/workspaces/{workspace_id}/resources": { + "/workspaces/{workspace_id}/vars/{id}": { "get": { - "operationId": "listWorkspaceResources", - "summary": "List Workspace Resources", - "description": "List all resources in a workspace's current state.", + "operationId": "showWorkspaceVar", + "summary": "Show a Variable", + "description": "Show details of a variable in a workspace.", "tags": [ - "workspaces" + "vars" ], "parameters": [ { @@ -6090,83 +6100,25 @@ "type": "string" }, "required": true, - "description": "The ID of the workspace to retrieve resources from." + "description": "The ID of the workspace." }, { - "in": "query", - "name": "q", + "in": "path", + "name": "id", "schema": { "type": "string" }, - "required": false, - "description": "Optional search query to filter resources by address pattern." - }, - { - "in": "query", - "name": "sort", - "schema": { - "type": "string", - "enum": [ - "name:asc", - "name:desc", - "nameIndex:asc", - "nameIndex:desc", - "provider:asc", - "provider:desc", - "providerType:asc", - "providerType:desc", - "module:asc", - "module:desc", - "updatedAt:asc", - "updatedAt:desc" - ] - }, - "required": false, - "description": "Optional sort parameter. Allows sorting workspace resources by name, nameIndex, provider, providerType, module, or updatedAt. Format is \"field:order\" where order is \"asc\" or \"desc\".\n" - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "required": true, + "description": "The ID of the variable." } ], "responses": { "200": { - "description": "List of workspace resources", - "content": { - "application/vnd.api+json": { - "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/workspace-resource" - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - } - } - } - } - } - }, - "404": { - "description": "Workspace not found or user unauthorized to perform action", + "description": "Variable details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/vars-envelope" } } } @@ -6182,15 +6134,13 @@ } } } - } - }, - "/workspaces/{workspace_id}": { - "get": { - "operationId": "getWorkspace", - "summary": "Get a Workspace", - "description": "Get details of a specific workspace by its external ID.", + }, + "patch": { + "operationId": "updateWorkspaceVar", + "summary": "Update a Variable", + "description": "Update attributes of an existing variable in a workspace.", "tags": [ - "workspaces" + "vars" ], "parameters": [ { @@ -6200,50 +6150,35 @@ "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The ID of the workspace." }, { - "in": "query", - "name": "include", + "in": "path", + "name": "id", "schema": { "type": "string" }, - "required": false, - "description": "Optionally side-load relationships. Comma-separated list of relationship names (e.g. current_run, current_state_version, locked_by, outputs, project, agent_pool).\n" + "required": true, + "description": "The ID of the variable." } ], - "responses": { - "200": { - "description": "Workspace details", - "content": { - "application/vnd.api+json": { - "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/workspaces-envelope" - }, - { - "type": "object", - "properties": { - "included": { - "type": "array", - "items": { - "type": "object" - } - } - } - } - ] - } + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/vars-envelope" } } - }, - "404": { - "description": "Workspace not found or user unauthorized to view workspace", + } + }, + "responses": { + "200": { + "description": "Variable updated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/vars-envelope" } } } @@ -6260,12 +6195,12 @@ } } }, - "patch": { - "operationId": "updateWorkspace", - "summary": "Update a Workspace", - "description": "Update settings of an existing workspace.", + "delete": { + "operationId": "deleteWorkspaceVar", + "summary": "Delete a Variable", + "description": "Delete a variable from a workspace.", "tags": [ - "workspaces" + "vars" ], "parameters": [ { @@ -6275,49 +6210,21 @@ "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The ID of the workspace." + }, + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the variable." } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-envelope" - } - } - } - }, "responses": { - "200": { - "description": "Workspace updated", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-envelope" - } - } - } - }, - "404": { - "description": "Workspace not found or user unauthorized to view workspace", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "422": { - "description": "Malformed request body", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } + "204": { + "description": "Variable deleted successfully" }, "default": { "description": "Error details", @@ -6330,35 +6237,37 @@ } } } - }, - "delete": { - "operationId": "deleteWorkspace", - "summary": "Delete a Workspace", - "description": "Delete a workspace. This permanently removes the workspace and all its associated data including runs, state versions, and configuration versions.\n", + } + }, + "/provider-sets/{provider_set_id}": { + "x-vis": [ + "public-beta" + ], + "get": { + "operationId": "showProviderSet", + "summary": "Show a Provider Set", + "description": "Fetch details about the specified provider set.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "provider-sets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "provider_set_id", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The ID of the provider set." } ], "responses": { - "204": { - "description": "Workspace deleted" - }, - "404": { - "description": "Workspace not found or user unauthorized to delete workspace", + "200": { + "description": "Provider set details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/provider-sets-envelope" } } } @@ -6374,64 +6283,42 @@ } } } - } - }, - "/workspaces/{workspace_id}/actions/lock": { - "post": { - "operationId": "lockWorkspace", - "summary": "Lock a Workspace", - "description": "Lock a workspace. A workspace can only be locked by one entity at a time. Returns a conflict error if the workspace is already locked.\n", + }, + "patch": { + "operationId": "updateProviderSet", + "summary": "Update a Provider Set", + "description": "Update attributes of an existing provider set.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "provider-sets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "provider_set_id", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The ID of the provider set." } ], "requestBody": { - "required": false, + "required": true, "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/action-reason" + "$ref": "#/components/schemas/provider-sets-envelope" } } } }, "responses": { "200": { - "description": "Workspace locked successfully", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-envelope" - } - } - } - }, - "404": { - "description": "Workspace not found or user unauthorized to lock workspace", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "409": { - "description": "Workspace is already locked", + "description": "Provider set updated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/provider-sets-envelope" } } } @@ -6447,57 +6334,28 @@ } } } - } - }, - "/workspaces/{workspace_id}/actions/unlock": { - "post": { - "operationId": "unlockWorkspace", - "summary": "Unlock a Workspace", - "description": "Unlock a workspace. Users can unlock a workspace if they locked it. Unlocking a workspace locked by another user requires force-unlock. Returns a conflict error if the workspace is not locked by the requesting user.\n", + }, + "delete": { + "operationId": "deleteProviderSet", + "summary": "Delete a Provider Set", + "description": "Delete an existing provider set.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "provider-sets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "provider_set_id", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The ID of the provider set." } ], "responses": { - "200": { - "description": "Workspace unlocked successfully", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-envelope" - } - } - } - }, - "404": { - "description": "Workspace not found or user unauthorized to unlock workspace", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "409": { - "description": "Workspace is locked by another user", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } + "204": { + "description": "Provider set deleted successfully" }, "default": { "description": "Error details", @@ -6512,45 +6370,41 @@ } } }, - "/workspaces/{workspace_id}/actions/force-unlock": { + "/provider-sets/{provider_set_id}/relationships/projects": { + "x-vis": [ + "public-beta" + ], "post": { - "operationId": "forceUnlockWorkspace", - "summary": "Force Unlock a Workspace", - "description": "Forcibly unlock a workspace regardless of who locked it. This action requires elevated permissions and should be used with caution.\n", + "operationId": "addProviderSetProjects", + "summary": "Add Projects to a Provider Set", + "description": "Add projects to a provider set. Relationships are additive; existing project assignments are preserved.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "provider-sets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "provider_set_id", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The ID of the provider set." } ], - "responses": { - "200": { - "description": "Workspace force-unlocked successfully", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-envelope" - } - } - } - }, - "404": { - "description": "Workspace not found or user unauthorized to force-unlock workspace", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/projects-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Projects successfully added to provider set." }, "default": { "description": "Error details", @@ -6563,50 +6417,38 @@ } } } - } - }, - "/workspaces/{workspace_id}/actions/safe-delete": { - "post": { - "operationId": "safeDeleteWorkspace", - "summary": "Safe Delete a Workspace", - "description": "Delete a workspace only if it has no resources under management. Returns a conflict error if the workspace has managed resources or is locked.\n", + }, + "delete": { + "operationId": "removeProviderSetProjects", + "summary": "Remove Projects from a Provider Set", + "description": "Remove projects from a provider set. Projects not currently assigned to the set are ignored.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "provider-sets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "provider_set_id", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The ID of the provider set." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/projects-identifier-array-document" + } + } + } + }, "responses": { "204": { - "description": "Workspace deleted" - }, - "404": { - "description": "Workspace not found or user unauthorized to delete workspace", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "409": { - "description": "Workspace has managed resources or is locked and cannot be safely deleted", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } + "description": "Projects successfully removed from provider set." }, "default": { "description": "Error details", @@ -6621,38 +6463,44 @@ } } }, - "/workspaces/{workspace_id}/actions/assess": { + "/provider-sets/{provider_set_id}/relationships/workspaces": { + "x-vis": [ + "public-beta" + ], "post": { - "operationId": "assessWorkspace", - "summary": "Trigger a Workspace Assessment", - "description": "Trigger a drift detection assessment for a workspace. The workspace must have assessments enabled and not have a pending assessment already running.\n", + "operationId": "addProviderSetWorkspaces", + "summary": "Add Workspaces to a Provider Set", + "description": "Add workspaces to a provider set. Relationships are additive; existing workspace assignments are preserved.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "provider-sets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "provider_set_id", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The ID of the provider set." } ], - "responses": { - "200": { - "description": "Assessment triggered successfully", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-envelope" - } + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspaces-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Workspaces successfully added to provider set." }, - "404": { - "description": "Workspace not found or user unauthorized to manage assessments", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -6660,16 +6508,40 @@ } } } - }, - "409": { - "description": "Assessment cannot be triggered in the current workspace state", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } + } + } + }, + "delete": { + "operationId": "removeProviderSetWorkspaces", + "summary": "Remove Workspaces from a Provider Set", + "description": "Remove workspaces from a provider set. Workspaces not currently assigned to the set are ignored.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", + "tags": [ + "provider-sets" + ], + "parameters": [ + { + "in": "path", + "name": "provider_set_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the provider set." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspaces-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Workspaces successfully removed from provider set." }, "default": { "description": "Error details", @@ -6684,66 +6556,53 @@ } } }, - "/workspaces/{workspace_id}/relationships/remote-state-consumers": { + "/organizations/{organization_name}/provider-sets": { + "x-vis": [ + "public-beta" + ], "get": { - "operationId": "listWorkspaceRemoteStateConsumers", - "summary": "List Remote State Consumers", - "description": "List the workspaces that are allowed to access this workspace's state. When global-remote-state is enabled on the workspace, this lists all workspaces in the organization; otherwise, it lists only the explicitly allowed consumers.\n", + "operationId": "getProviderSets", + "summary": "Get Provider Sets", + "description": "Fetch details about all the provider sets in an organization.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "provider-sets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." - }, - { - "in": "query", - "name": "show_only_configured", - "schema": { - "type": "boolean" - }, - "required": false, - "description": "When true, return only explicitly configured remote state consumers even if global-remote-state is enabled.\n" + "description": "The name of the organization." } ], "responses": { "200": { - "description": "List of workspaces that can consume this workspace's remote state", + "description": "Provider sets' details", "content": { "application/vnd.api+json": { "schema": { "type": "object", - "required": [ - "data" - ], "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/workspaces" + "$ref": "#/components/schemas/provider-sets" } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "$ref": "#/components/schemas/pagination" } } } } } }, - "404": { - "description": "Workspace not found or user unauthorized to view workspace", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, "default": { "description": "Error details", "content": { @@ -6757,21 +6616,21 @@ } }, "post": { - "operationId": "addWorkspaceRemoteStateConsumers", - "summary": "Add Remote State Consumers", - "description": "Add workspaces to the list of allowed remote state consumers.", + "operationId": "createProviderSet", + "summary": "Create a Provider Set", + "description": "Create a provider set belonging to an organization.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "provider-sets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The name of the organization." } ], "requestBody": { @@ -6779,21 +6638,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspaces-identifier-array-document" + "$ref": "#/components/schemas/provider-sets-envelope" } } } }, "responses": { - "204": { - "description": "Remote state consumers updated" - }, - "404": { - "description": "Workspace not found or user unauthorized to manage remote state consumers", + "201": { + "description": "Provider set created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/provider-sets-envelope" } } } @@ -6810,22 +6666,22 @@ } } }, - "patch": { - "operationId": "replaceWorkspaceRemoteStateConsumers", - "summary": "Replace Remote State Consumers", - "description": "Replace the entire list of allowed remote state consumers with the provided list.", + "delete": { + "operationId": "batchDeleteProviderSets", + "summary": "Batch Delete Provider Sets", + "description": "Delete multiple provider sets in a single request.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "provider-sets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The name of the organization." } ], "requestBody": { @@ -6833,24 +6689,33 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspaces-identifier-array-document" + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "provider-sets" + ] + }, + "id": { + "type": "string" + } + } + } + } + } } } } }, "responses": { "204": { - "description": "Remote state consumers replaced" - }, - "404": { - "description": "Workspace not found or user unauthorized to manage remote state consumers", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } + "description": "Provider sets deleted successfully" }, "default": { "description": "Error details", @@ -6863,45 +6728,46 @@ } } } - }, - "delete": { - "operationId": "removeWorkspaceRemoteStateConsumers", - "summary": "Remove Remote State Consumers", - "description": "Remove workspaces from the list of allowed remote state consumers.", + } + }, + "/organizations/{organization_name}/provider-sets/{provider_set_name}": { + "x-vis": [ + "public-beta" + ], + "get": { + "operationId": "showProviderSetByName", + "summary": "Show a Provider Set by name", + "description": "Fetch details about the specified provider set.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "provider-sets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The name of the organization." + }, + { + "in": "path", + "name": "provider_set_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the provider_set." } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-identifier-array-document" - } - } - } - }, "responses": { - "204": { - "description": "Remote state consumers removed" - }, - "404": { - "description": "Workspace not found or user unauthorized to manage remote state consumers", + "200": { + "description": "Provider set details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/provider-sets-envelope" } } } @@ -6919,52 +6785,49 @@ } } }, - "/workspaces/{workspace_id}/relationships/ssh-key": { - "patch": { - "operationId": "assignWorkspaceSshKey", - "summary": "Assign an SSH Key to a Workspace", - "description": "Assign an SSH key to a workspace for use when cloning VCS repositories. Pass null for the id to unassign the current SSH key.\n", + "/projects/{project_id}/provider-sets": { + "x-vis": [ + "public-beta" + ], + "get": { + "operationId": "getProjectProviderSets", + "summary": "Get Provider Sets", + "description": "Fetch details about all the provider sets assigned to a project.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "provider-sets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "project_id", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The id of a project." } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/ssh-keys-nullable-identifier-document" - } - } - } - }, "responses": { "200": { - "description": "SSH key assignment updated", + "description": "Provider sets' details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspaces-envelope" - } - } - } - }, - "404": { - "description": "Workspace or SSH key not found, or user unauthorized", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/provider-sets" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "$ref": "#/components/schemas/pagination" + } + } } } } @@ -6982,13 +6845,16 @@ } } }, - "/workspaces/{workspace_id}/relationships/vars": { - "patch": { - "operationId": "updateWorkspaceVars", - "summary": "Update Workspace Variables", - "description": "Batch update workspace variables. Provide an array of variable objects to update. Variables are matched by their external ID.\n", + "/workspaces/{workspace_id}/provider-sets": { + "x-vis": [ + "public-beta" + ], + "get": { + "operationId": "getWorkspaceProviderSets", + "summary": "Get Provider Sets", + "description": "Fetch details about all the provider sets assigned to a workspace.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "workspaces" + "provider-sets" ], "parameters": [ { @@ -6998,49 +6864,30 @@ "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The id of a workspace." } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspace-vars-update-document" - } - } - } - }, "responses": { - "204": { - "description": "Variables updated" - }, - "400": { - "description": "Too many variables or invalid request", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "404": { - "description": "Workspace not found or user unauthorized to update variables", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "422": { - "description": "Validation error on one or more variables", + "200": { + "description": "Provider sets' details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/provider-sets" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "$ref": "#/components/schemas/pagination" + } + } } } } @@ -7058,42 +6905,32 @@ } } }, - "/workspaces/{workspace_id}/relationships/tag-bindings": { + "/varsets/{varset_id}": { "get": { - "operationId": "listWorkspaceTagBindings", - "summary": "List Workspace Tags", - "description": "List all tags associated with a workspace.", + "operationId": "showVarset", + "summary": "Show a Variable Set", + "description": "Fetch details about the specified variable set.", "tags": [ - "workspaces" + "varsets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the workspace." + "description": "The ID of the variable set." } ], "responses": { "200": { - "description": "List of tags", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/tag-bindings-collection" - } - } - } - }, - "404": { - "description": "Workspace not found or user unauthorized to view workspace", + "description": "Variable set details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/varsets-envelope" } } } @@ -7110,22 +6947,22 @@ } } }, - "post": { - "operationId": "addWorkspaceTagBindings", - "summary": "Add Tag Bindings to a Workspace", - "description": "Add one or more tag bindings to a workspace.", + "patch": { + "operationId": "updateVarset", + "summary": "Update a Variable Set", + "description": "Update attributes of an existing variable set.", "tags": [ - "workspaces" + "varsets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The ID of the variable set." } ], "requestBody": { @@ -7133,21 +6970,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/tag-bindings-collection" + "$ref": "#/components/schemas/varsets-envelope" } } } }, "responses": { - "204": { - "description": "Tags added" - }, - "404": { - "description": "Workspace not found or user unauthorized to manage tags", + "200": { + "description": "Variable set updated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/varsets-envelope" } } } @@ -7164,22 +6998,22 @@ } } }, - "patch": { - "operationId": "replaceWorkspaceTagBindings", - "summary": "Replace Tag Bindings in a Workspace", - "description": "Replace all tag bindings in a workspace.", + "post": { + "operationId": "updateVarsetPost", + "summary": "Update a Variable Set (POST)", + "description": "Update attributes of an existing variable set using POST.", "tags": [ - "workspaces" + "varsets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the workspace." + "description": "The ID of the variable set." } ], "requestBody": { @@ -7187,21 +7021,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/tag-bindings-collection" + "$ref": "#/components/schemas/varsets-envelope" } } } }, "responses": { - "204": { - "description": "Tag bindings replaced" - }, - "404": { - "description": "Workspace not found or user unauthorized to manage tag bindings", + "200": { + "description": "Variable set updated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/varsets-envelope" } } } @@ -7217,77 +7048,28 @@ } } } - } - }, - "/workspaces/{workspace_id}/relationships/tags": { - "get": { - "operationId": "listWorkspaceTags", - "summary": "List Workspace Tags", - "description": "List all tags associated with a workspace.", + }, + "delete": { + "operationId": "deleteVarset", + "summary": "Delete a Variable Set", + "description": "Delete an existing variable set.", "tags": [ - "workspaces" + "varsets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The ID of the variable set." } ], "responses": { - "200": { - "description": "List of tags", - "content": { - "application/vnd.api+json": { - "schema": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "tags" - ] - }, - "attributes": { - "type": "object", - "properties": { - "name": { - "type": "string" - } - } - } - } - } - } - } - } - } - } - }, - "404": { - "description": "Workspace not found or user unauthorized to view workspace", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } + "204": { + "description": "Variable set deleted successfully" }, "default": { "description": "Error details", @@ -7300,45 +7082,84 @@ } } } - }, - "post": { - "operationId": "addWorkspaceTags", - "summary": "Add Tags to a Workspace", - "description": "Add one or more tags to a workspace.", + } + }, + "/organizations/{organization_name}/varsets": { + "get": { + "operationId": "listOrganizationVarsets", + "summary": "List Variable Sets for an Organization", + "description": "List all variable sets for an organization.", "tags": [ - "workspaces" + "varsets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/tags-create-array-document" - } - } - } - }, - "responses": { - "204": { - "description": "Tags added" + "description": "The name of the organization." }, - "404": { - "description": "Workspace not found or user unauthorized to manage tags", + { + "in": "query", + "name": "q", + "schema": { + "type": "string" + }, + "required": false, + "description": "A search query string. You can search for a variable set using its name." + }, + { + "in": "query", + "name": "filter[global]", + "schema": { + "type": "boolean" + }, + "required": false, + "description": "When true, returns only global variable sets. When false, returns only non-global variable sets." + }, + { + "in": "query", + "name": "scope", + "schema": { + "type": "string", + "enum": [ + "owned" + ] + }, + "required": false, + "description": "When set to \"owned\", returns only organization-owned variable sets." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of variable sets for the organization", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/varsets" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "$ref": "#/components/schemas/pagination" + } + } } } } @@ -7355,22 +7176,22 @@ } } }, - "delete": { - "operationId": "removeWorkspaceTags", - "summary": "Remove Tags from a Workspace", - "description": "Remove one or more tags from a workspace.", + "post": { + "operationId": "createVarset", + "summary": "Create a Variable Set", + "description": "Create a new variable set in an organization.", "tags": [ - "workspaces" + "varsets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The name of the organization." } ], "requestBody": { @@ -7378,21 +7199,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/tags-remove-array-document" + "$ref": "#/components/schemas/varsets-envelope" } } } }, "responses": { - "204": { - "description": "Tags removed" - }, - "404": { - "description": "Workspace not found or user unauthorized to manage tags", + "201": { + "description": "Variable set created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/varsets-envelope" } } } @@ -7410,47 +7228,52 @@ } } }, - "/workspaces/{workspace_id}/current-state-version": { + "/varsets/{varset_id}/relationships/vars": { "get": { - "operationId": "getCurrentStateVersion", - "summary": "Get Current State Version", - "description": "Get the current state version for a workspace.", + "operationId": "listVarsetVars", + "summary": "List Variables in a Variable Set", + "description": "List all variables in a variable set.", "tags": [ - "workspaces" + "varsets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." - }, - { - "in": "query", - "name": "include", - "schema": { - "type": "string" - }, - "required": false, - "description": "Optionally side-load relationships. For example, outputs or created-by.\n" + "description": "The ID of the variable set." } ], "responses": { "200": { - "description": "Current state version details", + "description": "List of variables in the variable set", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/current-state-version-envelope" + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/vars" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } } } } }, - "404": { - "description": "Workspace not found, no current state version exists, or user unauthorized", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -7458,6 +7281,47 @@ } } } + } + } + }, + "post": { + "operationId": "addVarsetVar", + "summary": "Add a Variable to a Variable Set", + "description": "Add a new variable to an existing variable set.", + "tags": [ + "varsets" + ], + "parameters": [ + { + "in": "path", + "name": "varset_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the variable set." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/vars-envelope" + } + } + } + }, + "responses": { + "201": { + "description": "Variable added to variable set", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/vars-envelope" + } + } + } }, "default": { "description": "Error details", @@ -7472,42 +7336,41 @@ } } }, - "/workspaces/{workspace_id}/current-assessment-result": { + "/varsets/{varset_id}/relationships/vars/{id}": { "get": { - "operationId": "getCurrentAssessmentResult", - "summary": "Get Current Assessment Result", - "description": "Get the most recent drift detection assessment result for a workspace.", + "operationId": "showVarsetVar", + "summary": "Show a Variable in a Variable Set", + "description": "Show details of a variable in a variable set.", "tags": [ - "workspaces" + "varsets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The ID of the variable set." + }, + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the variable." } ], "responses": { "200": { - "description": "Current assessment result", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/assessment-results-envelope" - } - } - } - }, - "404": { - "description": "Workspace not found, no current assessment result exists, or user unauthorized", + "description": "Variable details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/vars-envelope" } } } @@ -7523,135 +7386,51 @@ } } } - } - }, - "/workspaces/{workspace_id}/applicable-varsets": { - "get": { - "operationId": "listApplicableVarsets", - "summary": "List Applicable Variable Sets", - "description": "List the variable sets that can be applied to a workspace. This returns variable sets from the workspace's organization that are not already applied to the workspace, filtered by project scope.\n", + }, + "patch": { + "operationId": "updateVarsetVar", + "summary": "Update a Variable in a Variable Set", + "description": "Update attributes of an existing variable in a variable set.", "tags": [ - "workspaces" + "varsets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "The external ID of the workspace." + "description": "The ID of the variable set." }, { - "in": "query", - "name": "q", + "in": "path", + "name": "id", "schema": { "type": "string" }, - "required": false, - "description": "Optional search query to filter variable sets by name." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "required": true, + "description": "The ID of the variable to update." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/vars-envelope" + } + } + } + }, "responses": { "200": { - "description": "List of applicable variable sets", + "description": "Variable updated", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "varsets" - ] - }, - "attributes": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "global": { - "type": "boolean" - }, - "auto-apply": { - "type": "boolean" - }, - "var-count": { - "type": "integer" - }, - "workspace-count": { - "type": "integer" - }, - "project-count": { - "type": "integer" - }, - "created-at": { - "type": "string", - "format": "date-time", - "readOnly": true - }, - "updated-at": { - "type": "string", - "format": "date-time", - "readOnly": true - } - } - } - } - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - }, - "status-counts": { - "type": "object", - "additionalProperties": { - "type": "integer" - } - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } - } - } - } - }, - "404": { - "description": "Workspace not found or user unauthorized to view workspace", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/vars-envelope" } } } @@ -7667,36 +7446,37 @@ } } } - } - }, - "/runs": { - "post": { - "operationId": "createRun", - "summary": "Create a Run", - "description": "Create a new run.", + }, + "delete": { + "operationId": "deleteVarsetVar", + "summary": "Delete a Variable from a Variable Set", + "description": "Delete a variable from a variable set.", "tags": [ - "runs" + "varsets" ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/runs-envelope" - } - } + "parameters": [ + { + "in": "path", + "name": "varset_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the variable set." + }, + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the variable to delete." } - }, + ], "responses": { - "201": { - "description": "Run created", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/runs-envelope" - } - } - } + "204": { + "description": "Variable deleted successfully" }, "default": { "description": "Error details", @@ -7709,84 +7489,52 @@ } } } - }, + } + }, + "/workspaces/{workspace_id}/varsets/{varset_id}/relationships/vars/{id}": { "get": { - "operationId": "listRuns", - "summary": "List Runs", - "description": "List all runs in a workspace.", + "operationId": "showWorkspaceVarsetVar", + "summary": "Show a Variable in a Variable Set (Workspace Context)", + "description": "Show details of a variable in a variable set, with overwrite context from the specified workspace.", "tags": [ - "runs" + "varsets" ], "parameters": [ { - "in": "query", + "in": "path", "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "Workspace ID" + "description": "The ID of the workspace providing overwrite context." }, { - "in": "query", - "name": "organization_name", + "in": "path", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "Organization Name" - }, - { - "in": "query", - "name": "filter[operation]", - "schema": { - "type": "string" - }, - "required": false, - "description": "Filter by run operation." + "description": "The ID of the variable set." }, { - "in": "query", - "name": "filter[status]", + "in": "path", + "name": "id", "schema": { "type": "string" }, - "required": false, - "description": "Filter by run status." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "required": true, + "description": "The ID of the variable." } ], "responses": { "200": { - "description": "List of runs", + "description": "Variable details with workspace overwrite context", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/runs" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } + "$ref": "#/components/schemas/vars-envelope" } } } @@ -7804,32 +7552,55 @@ } } }, - "/runs/{run_id}": { + "/workspaces/{workspace_id}/varsets/{varset_id}/relationships/vars": { "get": { - "operationId": "getRun", - "summary": "Get Run details", - "description": "Get details about a run.", + "operationId": "listWorkspaceVarsetVars", + "summary": "List Variables in a Variable Set (Workspace Context)", + "description": "List all variables in a variable set, with overwrite context from the specified workspace.", "tags": [ - "runs" + "varsets" ], "parameters": [ { "in": "path", - "name": "run_id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "Run ID" + "description": "The ID of the workspace providing overwrite context." + }, + { + "in": "path", + "name": "varset_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the variable set." } ], "responses": { "200": { - "description": "Run details", + "description": "List of variables in the variable set with workspace overwrite context", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/runs-envelope" + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/vars" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } } } } @@ -7847,35 +7618,38 @@ } } }, - "/runs/{run_id}/configuration-version": { - "get": { - "operationId": "getRunConfigurationVersion", - "summary": "Get Run Configuration Version", - "description": "Get details of a specific configuration version.", - "tags": [ - "configuration-versions" - ], + "/varsets/{varset_id}/relationships/projects": { + "post": { + "operationId": "applyVarsetToProjects", + "summary": "Apply Variable Set to Projects", + "description": "Apply a variable set to one or more projects. When you apply a variable set to a project, all the workspaces in that project will have the variable set applied to them.", + "tags": [ + "varsets" + ], "parameters": [ { "in": "path", - "name": "run_id", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the run" + "description": "The ID of the variable set." } ], - "responses": { - "200": { - "description": "Configuration version details", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/configuration-versions-envelope" - } + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/projects-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Variable set successfully applied to the requested projects." }, "default": { "description": "Error details", @@ -7888,38 +7662,38 @@ } } } - } - }, - "/runs/{run_id}/configuration-version/download": { - "get": { - "operationId": "downloadRunConfigurationVersion", - "summary": "Download Run Configuration Version", - "description": "Generate a temporary URL to download the configuration version files.", + }, + "delete": { + "operationId": "removeVarsetFromProjects", + "summary": "Remove Variable Set from Projects", + "description": "Remove a variable set from one or more projects.", "tags": [ - "configuration-versions" + "varsets" ], "parameters": [ { "in": "path", - "name": "run_id", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the run." + "description": "The ID of the variable set." } ], - "responses": { - "302": { - "description": "Temporary download URL generated", - "headers": { - "Location": { - "description": "Storage URL to .tar.gz file containing the configuration version", - "schema": { - "type": "string" - } + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/projects-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Variable set successfully removed from the requested projects." }, "default": { "description": "Error details", @@ -7934,60 +7708,38 @@ } } }, - "/runs/{run_id}/comments": { - "get": { - "operationId": "listRunComments", - "summary": "List Comments for a Run", - "description": "List all comments for a run.", + "/varsets/{varset_id}/relationships/workspaces": { + "post": { + "operationId": "applyVarsetToWorkspaces", + "summary": "Apply Variable Set to Workspaces", + "description": "Apply a variable set to one or more workspaces.", "tags": [ - "comments" + "varsets" ], "parameters": [ { "in": "path", - "name": "run_id", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "Run ID" - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "The ID of the variable set." } ], - "responses": { - "200": { - "description": "List of comments", - "content": { - "application/vnd.api+json": { - "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/comments" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } - } + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspaces-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Variable set successfully applied to the requested workspaces." }, "default": { "description": "Error details", @@ -8001,22 +7753,22 @@ } } }, - "post": { - "operationId": "createRunComment", - "summary": "Create a Comment", - "description": "Create a new comment on a run.", + "delete": { + "operationId": "removeVarsetFromWorkspaces", + "summary": "Remove Variable Set from Workspaces", + "description": "Remove a variable set from one or more workspaces.", "tags": [ - "comments" + "varsets" ], "parameters": [ { "in": "path", - "name": "run_id", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "Run ID" + "description": "The ID of the variable set." } ], "requestBody": { @@ -8024,21 +7776,14 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/comments-envelope" + "$ref": "#/components/schemas/workspaces-identifier-array-document" } } } }, "responses": { - "201": { - "description": "Comment created", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/comments-envelope" - } - } - } + "204": { + "description": "Variable set successfully removed from the requested workspaces." }, "default": { "description": "Error details", @@ -8053,35 +7798,38 @@ } } }, - "/comments/{id}": { - "get": { - "operationId": "showComment", - "summary": "Show a Comment", - "description": "Get details about a comment.", + "/varsets/{varset_id}/relationships/stacks": { + "post": { + "operationId": "applyVarsetToStacks", + "summary": "Apply Variable Set to Stacks", + "description": "Apply a variable set to one or more Stacks. Only available in HCP Terraform.", "tags": [ - "comments" + "varsets" ], "parameters": [ { "in": "path", - "name": "id", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "Comment ID" + "description": "The ID of the variable set." } ], - "responses": { - "200": { - "description": "Comment details", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/comments-envelope" - } + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/jsonapi-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Variable set successfully applied to the requested Stacks." }, "default": { "description": "Error details", @@ -8094,43 +7842,41 @@ } } } - } - }, - "/runs/{run_id}/actions/apply": { - "post": { - "operationId": "applyRun", - "summary": "Apply a Run", - "description": "Apply a run that is paused waiting for confirmation.", + }, + "delete": { + "operationId": "removeVarsetFromStacks", + "summary": "Remove Variable Set from Stacks", + "description": "Remove a variable set from one or more Stacks.", "tags": [ - "runs" + "varsets" ], "parameters": [ { "in": "path", - "name": "run_id", + "name": "varset_id", "schema": { "type": "string" }, "required": true, - "description": "Run ID" + "description": "The ID of the variable set." } ], "requestBody": { - "required": false, + "required": true, "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/action-comment" + "$ref": "#/components/schemas/jsonapi-identifier-array-document" } } } }, "responses": { - "202": { - "description": "Successfully queued an apply request" + "204": { + "description": "Variable set successfully removed from the requested Stacks." }, - "409": { - "description": "Run was not paused for confirmation; apply not allowed.", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -8142,41 +7888,47 @@ } } }, - "/workspaces/{workspace_id}/runs": { + "/projects/{project_id}/varsets": { "get": { - "operationId": "listWorkspaceRuns", - "summary": "List Runs in a Workspace", - "description": "List all runs in a workspace.", + "operationId": "listProjectVarsets", + "summary": "List Variable Sets for a Project", + "description": "List all variable sets for a project. This includes global variable sets from the project's organization.", "tags": [ - "runs" + "varsets" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "project_id", "schema": { "type": "string" }, "required": true, - "description": "Workspace ID" + "description": "The ID of the project." }, { "in": "query", - "name": "filter[operation]", + "name": "q", "schema": { "type": "string" }, "required": false, - "description": "Filter by run operation." + "description": "A search query string. You can search for a variable set using its name." }, { "in": "query", - "name": "filter[status]", + "name": "scope", "schema": { - "type": "string" + "type": "string", + "enum": [ + "applied", + "shared", + "owned", + "all" + ] }, "required": false, - "description": "Filter by run status." + "description": "Filter variable sets by scope relative to the project." }, { "$ref": "#/components/parameters/page_number" @@ -8187,7 +7939,7 @@ ], "responses": { "200": { - "description": "List of runs", + "description": "List of variable sets for the project", "content": { "application/vnd.api+json": { "schema": { @@ -8196,19 +7948,14 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/runs" + "$ref": "#/components/schemas/varsets" } }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" + "$ref": "#/components/schemas/pagination" } } } @@ -8228,13 +7975,13 @@ } } }, - "/workspaces/{workspace_id}/run-triggers": { + "/workspaces/{workspace_id}/varsets": { "get": { - "operationId": "listRunTriggers", - "summary": "List Run Triggers", - "description": "List all run triggers for a workspace.", + "operationId": "listWorkspaceVarsets", + "summary": "List Variable Sets for a Workspace", + "description": "List all variable sets for a workspace. This includes global variable sets from the workspace's organization and variable sets attached to the project this workspace is contained within.", "tags": [ - "run-triggers" + "varsets" ], "parameters": [ { @@ -8244,20 +7991,16 @@ "type": "string" }, "required": true, - "description": "Workspace ID" + "description": "The ID of the workspace." }, { "in": "query", - "name": "filter[run-trigger][type]", + "name": "q", "schema": { - "type": "string", - "enum": [ - "inbound", - "outbound" - ] + "type": "string" }, - "required": true, - "description": "Filter by run trigger type (inbound or outbound)" + "required": false, + "description": "A search query string. You can search for a variable set using its name." }, { "$ref": "#/components/parameters/page_number" @@ -8268,7 +8011,7 @@ ], "responses": { "200": { - "description": "List of run triggers", + "description": "List of variable sets for the workspace", "content": { "application/vnd.api+json": { "schema": { @@ -8277,19 +8020,14 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/run-triggers" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } + "$ref": "#/components/schemas/varsets" } }, "links": { "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "$ref": "#/components/schemas/pagination" } } } @@ -8307,13 +8045,15 @@ } } } - }, - "post": { - "operationId": "createRunTrigger", - "summary": "Create a Run Trigger", - "description": "Create a new run trigger for a workspace.", + } + }, + "/workspaces/{workspace_id}/resources": { + "get": { + "operationId": "listWorkspaceResources", + "summary": "List Workspace Resources", + "description": "List all resources in a workspace's current state.", "tags": [ - "run-triggers" + "workspaces" ], "parameters": [ { @@ -8323,26 +8063,83 @@ "type": "string" }, "required": true, - "description": "Workspace ID" + "description": "The ID of the workspace to retrieve resources from." + }, + { + "in": "query", + "name": "q", + "schema": { + "type": "string" + }, + "required": false, + "description": "Optional search query to filter resources by address pattern." + }, + { + "in": "query", + "name": "sort", + "schema": { + "type": "string", + "enum": [ + "name:asc", + "name:desc", + "nameIndex:asc", + "nameIndex:desc", + "provider:asc", + "provider:desc", + "providerType:asc", + "providerType:desc", + "module:asc", + "module:desc", + "updatedAt:asc", + "updatedAt:desc" + ] + }, + "required": false, + "description": "Optional sort parameter. Allows sorting workspace resources by name, nameIndex, provider, providerType, module, or updatedAt. Format is \"field:order\" where order is \"asc\" or \"desc\".\n" + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/run-triggers-envelope" + "responses": { + "200": { + "description": "List of workspace resources", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/workspace-resource" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + } + } + } } } - } - }, - "responses": { - "201": { - "description": "Run trigger created", + }, + "404": { + "description": "Workspace not found or user unauthorized to perform action", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/run-triggers-envelope" + "$ref": "#/components/schemas/errors" } } } @@ -8360,32 +8157,66 @@ } } }, - "/run-triggers/{id}": { + "/workspaces/{workspace_id}": { "get": { - "operationId": "showRunTrigger", - "summary": "Show a Run Trigger", - "description": "Get details about a run trigger.", + "operationId": "getWorkspace", + "summary": "Get a Workspace", + "description": "Get details of a specific workspace by its external ID.", "tags": [ - "run-triggers" + "workspaces" ], "parameters": [ { "in": "path", - "name": "id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "Run Trigger ID" + "description": "The external ID of the workspace." + }, + { + "in": "query", + "name": "include", + "schema": { + "type": "string" + }, + "required": false, + "description": "Optionally side-load relationships. Comma-separated list of relationship names (e.g. current_run, current_state_version, locked_by, outputs, project, agent_pool).\n" } ], "responses": { "200": { - "description": "Run trigger details", + "description": "Workspace details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/run-triggers-envelope" + "allOf": [ + { + "$ref": "#/components/schemas/workspaces-envelope" + }, + { + "type": "object", + "properties": { + "included": { + "type": "array", + "items": { + "type": "object" + } + } + } + } + ] + } + } + } + }, + "404": { + "description": "Workspace not found or user unauthorized to view workspace", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -8402,27 +8233,64 @@ } } }, - "delete": { - "operationId": "deleteRunTrigger", - "summary": "Delete a Run Trigger", - "description": "Delete a run trigger.", + "patch": { + "operationId": "updateWorkspace", + "summary": "Update a Workspace", + "description": "Update settings of an existing workspace.", "tags": [ - "run-triggers" + "workspaces" ], "parameters": [ { "in": "path", - "name": "id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "Run Trigger ID" + "description": "The external ID of the workspace." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspaces-envelope" + } + } + } + }, "responses": { - "204": { - "description": "Run trigger deleted" + "200": { + "description": "Workspace updated", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspaces-envelope" + } + } + } + }, + "404": { + "description": "Workspace not found or user unauthorized to view workspace", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Malformed request body", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } }, "default": { "description": "Error details", @@ -8435,87 +8303,35 @@ } } } - } - }, - "/organizations/{organization_name}/runs": { - "get": { - "operationId": "listOrganizationRuns", - "summary": "List Runs in an Organization", - "description": "List all runs in an organization.", + }, + "delete": { + "operationId": "deleteWorkspace", + "summary": "Delete a Workspace", + "description": "Delete a workspace. This permanently removes the workspace and all its associated data including runs, state versions, and configuration versions.\n", "tags": [ - "runs" + "workspaces" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "Organization name" - }, - { - "in": "query", - "name": "filter[operation]", - "schema": { - "type": "string" - }, - "required": false, - "description": "Filter by run operation." - }, - { - "in": "query", - "name": "filter[status]", - "schema": { - "type": "string" - }, - "required": false, - "description": "Filter by run status." - }, - { - "in": "query", - "name": "filter[timeframe]", - "schema": { - "type": "string", - "default": "year" - }, - "required": false, - "description": "Filter by timeframe. Must be a numeric year or \"year\" for the last 12 months (the default)." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "The external ID of the workspace." } ], "responses": { - "200": { - "description": "List of runs", + "204": { + "description": "Workspace deleted" + }, + "404": { + "description": "Workspace not found or user unauthorized to delete workspace", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/runs" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination-without-totals" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } + "$ref": "#/components/schemas/errors" } } } @@ -8533,38 +8349,48 @@ } } }, - "/plans/{id}": { - "get": { + "/workspaces/{workspace_id}/actions/lock": { + "post": { + "operationId": "lockWorkspace", + "summary": "Lock a Workspace", + "description": "Lock a workspace. A workspace can only be locked by one entity at a time. Returns a conflict error if the workspace is already locked.\n", + "tags": [ + "workspaces" + ], "parameters": [ { - "name": "id", "in": "path", - "description": "The ID of the plan to show.", - "required": true, + "name": "workspace_id", "schema": { "type": "string" - } + }, + "required": true, + "description": "The external ID of the workspace." } ], - "operationId": "showPlan", - "summary": "Show a plan", - "description": "This endpoint returns a specific plan by its ID.", - "tags": [ - "plans" - ], + "requestBody": { + "required": false, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/action-reason" + } + } + } + }, "responses": { "200": { - "description": "Successfully returned the plan.", + "description": "Workspace locked successfully", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/plans-envelope" + "$ref": "#/components/schemas/workspaces-envelope" } } } }, - "default": { - "description": "Error details", + "404": { + "description": "Workspace not found or user unauthorized to lock workspace", "content": { "application/vnd.api+json": { "schema": { @@ -8572,46 +8398,9 @@ } } } - } - } - } - }, - "/plans/{id}/json-output": { - "get": { - "operationId": "getPlanJSONOutput", - "summary": "Get the JSON execution plan", - "description": "This endpoint generates a temporary authenticated URL to the location of the JSON formatted execution plan.\nWhen successful, this endpoint responds with a temporary redirect that should be followed.\n\nThis endpoint is available for plans using Terraform 0.12 and later.\nThe temporary URL has a life of 1 minute and should not be relied upon beyond the initial request.\n", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "The ID of the plan to show.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "tags": [ - "plans" - ], - "responses": { - "204": { - "description": "Plan JSON supported, but plan has not yet completed." - }, - "307": { - "description": "Plan JSON found and temporary download URL generated.", - "headers": { - "Location": { - "description": "Temporary URL to download the JSON output", - "schema": { - "type": "string" - } - } - } }, - "422": { - "description": "Plan does not use a supported version of Terraform (< 0.12.X).", + "409": { + "description": "Workspace is already locked", "content": { "application/vnd.api+json": { "schema": { @@ -8633,42 +8422,48 @@ } } }, - "/runs/{id}/plan/json-schema": { - "get": { - "operationId": "getPlanJSONSchemaOutput", - "summary": "Get the JSON provider schema corresponding to a plan", - "description": "This endpoint generates a temporary authenticated URL to the location of the JSON formatted provider schema.\nWhen successful, this endpoint responds with a temporary redirect that should be followed.\n\nThis endpoint is available for plans using Terraform 0.12 and later.\nThe temporary URL has a life of 1 minute and should not be relied upon beyond the initial request.\n", + "/workspaces/{workspace_id}/actions/unlock": { + "post": { + "operationId": "unlockWorkspace", + "summary": "Unlock a Workspace", + "description": "Unlock a workspace. Users can unlock a workspace if they locked it. Unlocking a workspace locked by another user requires force-unlock. Returns a conflict error if the workspace is not locked by the requesting user.\n", + "tags": [ + "workspaces" + ], "parameters": [ { - "name": "id", "in": "path", - "description": "The ID of the plan to show.", - "required": true, + "name": "workspace_id", "schema": { "type": "string" - } + }, + "required": true, + "description": "The external ID of the workspace." } ], - "tags": [ - "plans" - ], "responses": { - "204": { - "description": "Plan JSON supported, but plan has not yet completed." + "200": { + "description": "Workspace unlocked successfully", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspaces-envelope" + } + } + } }, - "307": { - "description": "Plan JSON found and temporary download URL generated.", - "headers": { - "Location": { - "description": "Temporary URL to download the JSON schema output", + "404": { + "description": "Workspace not found or user unauthorized to unlock workspace", + "content": { + "application/vnd.api+json": { "schema": { - "type": "string" + "$ref": "#/components/schemas/errors" } } } }, - "422": { - "description": "Plan does not use a supported version of Terraform (< 0.12.X).", + "409": { + "description": "Workspace is locked by another user", "content": { "application/vnd.api+json": { "schema": { @@ -8690,32 +8485,42 @@ } } }, - "/runs/{id}/plan": { - "get": { + "/workspaces/{workspace_id}/actions/force-unlock": { + "post": { + "operationId": "forceUnlockWorkspace", + "summary": "Force Unlock a Workspace", + "description": "Forcibly unlock a workspace regardless of who locked it. This action requires elevated permissions and should be used with caution.\n", + "tags": [ + "workspaces" + ], "parameters": [ { - "name": "id", "in": "path", - "description": "The ID of the run whose plan you want to get.", - "required": true, + "name": "workspace_id", "schema": { "type": "string" - } + }, + "required": true, + "description": "The external ID of the workspace." } ], - "operationId": "getRunPlan", - "summary": "Get a plan by Run ID", - "description": "This endpoint returns a specific plan by its run ID.", - "tags": [ - "plans" - ], "responses": { "200": { - "description": "Successfully returned the plan.", + "description": "Workspace force-unlocked successfully", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/plans-envelope" + "$ref": "#/components/schemas/workspaces-envelope" + } + } + } + }, + "404": { + "description": "Workspace not found or user unauthorized to force-unlock workspace", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -8733,42 +8538,41 @@ } } }, - "/runs/{id}/plan/json-output": { - "get": { - "operationId": "getRunPlanJsonOutput", - "summary": "Get the JSON execution plan by Run ID", - "description": "This endpoint generates a temporary authenticated URL to the location of the JSON formatted execution plan.\nWhen successful, this endpoint responds with a temporary redirect that should be followed.\n\nThis endpoint is available for plans using Terraform 0.12 and later.\nThe temporary URL has a life of 1 minute and should not be relied upon beyond the initial request.\n", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "The ID of the run whose plan json you want to get.", - "required": true, + "/workspaces/{workspace_id}/actions/safe-delete": { + "post": { + "operationId": "safeDeleteWorkspace", + "summary": "Safe Delete a Workspace", + "description": "Delete a workspace only if it has no resources under management. Returns a conflict error if the workspace has managed resources or is locked.\n", + "tags": [ + "workspaces" + ], + "parameters": [ + { + "in": "path", + "name": "workspace_id", "schema": { "type": "string" - } + }, + "required": true, + "description": "The external ID of the workspace." } ], - "tags": [ - "plans" - ], "responses": { "204": { - "description": "Plan JSON supported, but plan has not yet completed." + "description": "Workspace deleted" }, - "307": { - "description": "Plan JSON found and temporary download URL generated.", - "headers": { - "Location": { - "description": "Temporary URL to download the JSON output", + "404": { + "description": "Workspace not found or user unauthorized to delete workspace", + "content": { + "application/vnd.api+json": { "schema": { - "type": "string" + "$ref": "#/components/schemas/errors" } } } }, - "422": { - "description": "Plan does not use a supported version of Terraform (< 0.12.X).", + "409": { + "description": "Workspace has managed resources or is locked and cannot be safely deleted", "content": { "application/vnd.api+json": { "schema": { @@ -8790,39 +8594,38 @@ } } }, - "/policies/{policy_id}": { - "get": { - "operationId": "showPolicy", - "summary": "Show a Policy", - "description": "Get details about a policy.", + "/workspaces/{workspace_id}/actions/assess": { + "post": { + "operationId": "assessWorkspace", + "summary": "Trigger a Workspace Assessment", + "description": "Trigger a drift detection assessment for a workspace. The workspace must have assessments enabled and not have a pending assessment already running.\n", "tags": [ - "policies" + "workspaces" ], "parameters": [ { - "name": "policy_id", "in": "path", - "required": true, - "description": "The ID of the policy to show.", + "name": "workspace_id", "schema": { - "type": "string", - "example": "pol-xxxxxxxxxxxxxxxx" - } + "type": "string" + }, + "required": true, + "description": "The external ID of the workspace." } ], "responses": { "200": { - "description": "OK", + "description": "Assessment triggered successfully", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/policies-envelope" + "$ref": "#/components/schemas/workspaces-envelope" } } } }, - "default": { - "description": "Error details", + "404": { + "description": "Workspace not found or user unauthorized to manage assessments", "content": { "application/vnd.api+json": { "schema": { @@ -8830,51 +8633,9 @@ } } } - } - } - }, - "patch": { - "operationId": "updatePolicy", - "summary": "Update a Policy", - "description": "Update the enforcement level or description of an existing policy. To update the policy code itself, use the upload endpoint.", - "tags": [ - "policies" - ], - "parameters": [ - { - "name": "policy_id", - "in": "path", - "required": true, - "description": "The ID of the policy to update.", - "schema": { - "type": "string", - "example": "pol-xxxxxxxxxxxxxxxx" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/policies-envelope" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/policies-envelope" - } - } - } }, - "default": { - "description": "Error details", + "409": { + "description": "Assessment cannot be triggered in the current workspace state", "content": { "application/vnd.api+json": { "schema": { @@ -8882,31 +8643,6 @@ } } } - } - } - }, - "delete": { - "operationId": "deletePolicy", - "summary": "Delete a Policy", - "description": "Delete a policy from an organization.", - "tags": [ - "policies" - ], - "parameters": [ - { - "name": "policy_id", - "in": "path", - "required": true, - "description": "The ID of the policy to delete.", - "schema": { - "type": "string", - "example": "pol-xxxxxxxxxxxxxxxx" - } - } - ], - "responses": { - "204": { - "description": "No Content" }, "default": { "description": "Error details", @@ -8921,86 +8657,49 @@ } } }, - "/organizations/{organization_name}/policies": { + "/workspaces/{workspace_id}/relationships/remote-state-consumers": { "get": { - "operationId": "listPolicies", - "summary": "List Policies", - "description": "List all policies for an organization.", + "operationId": "listWorkspaceRemoteStateConsumers", + "summary": "List Remote State Consumers", + "description": "List the workspaces that are allowed to access this workspace's state. When global-remote-state is enabled on the workspace, this lists all workspaces in the organization; otherwise, it lists only the explicitly allowed consumers.\n", "tags": [ - "policies" + "workspaces" ], "parameters": [ { - "name": "organization_name", "in": "path", - "required": true, - "description": "The name of the organization.", - "schema": { - "type": "string", - "example": "my-organization" - } - }, - { - "name": "search[name]", - "in": "query", - "required": false, - "description": "Allows searching the organization's policies by name.", + "name": "workspace_id", "schema": { "type": "string" - } + }, + "required": true, + "description": "The external ID of the workspace." }, { - "name": "filter[kind]", "in": "query", - "required": false, - "description": "Filter policies by kind. Valid values are sentinel and opa.", + "name": "show_only_configured", "schema": { - "type": "string", - "enum": [ - "sentinel", - "opa" - ] - } - }, - { - "name": "sort", - "in": "query", + "type": "boolean" + }, "required": false, - "description": "Sort policies by the specified field. Valid values are name, -name, updated-at, and -updated-at. Prefix with - for descending order.", - "schema": { - "type": "string" - } - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "When true, return only explicitly configured remote state consumers even if global-remote-state is enabled.\n" } ], "responses": { "200": { - "description": "OK", + "description": "List of workspaces that can consume this workspace's remote state", "content": { "application/vnd.api+json": { "schema": { "type": "object", + "required": [ + "data" + ], "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/policies" - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } + "$ref": "#/components/schemas/workspaces" } } } @@ -9008,6 +8707,16 @@ } } }, + "404": { + "description": "Workspace not found or user unauthorized to view workspace", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, "default": { "description": "Error details", "content": { @@ -9021,22 +8730,21 @@ } }, "post": { - "operationId": "createPolicy", - "summary": "Create a Policy", - "description": "Create a new policy object for the organization. After creation, upload the policy code using the upload endpoint.", + "operationId": "addWorkspaceRemoteStateConsumers", + "summary": "Add Remote State Consumers", + "description": "Add workspaces to the list of allowed remote state consumers.", "tags": [ - "policies" + "workspaces" ], "parameters": [ { - "name": "organization_name", "in": "path", - "required": true, - "description": "The name of the organization.", + "name": "workspace_id", "schema": { - "type": "string", - "example": "my-organization" - } + "type": "string" + }, + "required": true, + "description": "The external ID of the workspace." } ], "requestBody": { @@ -9044,18 +8752,21 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/policies-envelope" + "$ref": "#/components/schemas/workspaces-identifier-array-document" } } } }, "responses": { - "201": { - "description": "Created", + "204": { + "description": "Remote state consumers updated" + }, + "404": { + "description": "Workspace not found or user unauthorized to manage remote state consumers", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/policies-envelope" + "$ref": "#/components/schemas/errors" } } } @@ -9071,36 +8782,45 @@ } } } - } - }, - "/policies/{policy_id}/download": { - "get": { - "operationId": "downloadPolicy", - "summary": "Download a Policy", - "description": "Generate a temporary URL to the current version of the policy code and redirect to that location. Returns 404 if no policy code has been uploaded.", + }, + "patch": { + "operationId": "replaceWorkspaceRemoteStateConsumers", + "summary": "Replace Remote State Consumers", + "description": "Replace the entire list of allowed remote state consumers with the provided list.", "tags": [ - "policies" + "workspaces" ], "parameters": [ { - "name": "policy_id", "in": "path", - "required": true, - "description": "The ID of the policy to download.", + "name": "workspace_id", "schema": { - "type": "string", - "example": "pol-xxxxxxxxxxxxxxxx" - } + "type": "string" + }, + "required": true, + "description": "The external ID of the workspace." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspaces-identifier-array-document" + } + } + } + }, "responses": { - "302": { - "description": "Redirect to the temporary download URL for the policy code", - "headers": { - "Location": { - "description": "Temporary storage URL for the policy code", + "204": { + "description": "Remote state consumers replaced" + }, + "404": { + "description": "Workspace not found or user unauthorized to manage remote state consumers", + "content": { + "application/vnd.api+json": { "schema": { - "type": "string" + "$ref": "#/components/schemas/errors" } } } @@ -9116,47 +8836,45 @@ } } } - } - }, - "/policies/{policy_id}/upload": { - "put": { - "operationId": "uploadPolicy", - "summary": "Upload a Policy", - "description": "Upload code to an existing Sentinel or OPA policy. The request body must be the policy code with a Content-Type of application/octet-stream. Policy uploads are limited to 10MB.", + }, + "delete": { + "operationId": "removeWorkspaceRemoteStateConsumers", + "summary": "Remove Remote State Consumers", + "description": "Remove workspaces from the list of allowed remote state consumers.", "tags": [ - "policies" + "workspaces" ], "parameters": [ { - "name": "policy_id", "in": "path", - "required": true, - "description": "The ID of the policy to upload code to.", + "name": "workspace_id", "schema": { - "type": "string", - "example": "pol-xxxxxxxxxxxxxxxx" - } + "type": "string" + }, + "required": true, + "description": "The external ID of the workspace." } ], "requestBody": { "required": true, "content": { - "application/octet-stream": { + "application/vnd.api+json": { "schema": { - "type": "string", - "format": "binary", - "description": "The policy code as a binary stream." + "$ref": "#/components/schemas/workspaces-identifier-array-document" } } } }, "responses": { - "200": { - "description": "OK", + "204": { + "description": "Remote state consumers removed" + }, + "404": { + "description": "Workspace not found or user unauthorized to manage remote state consumers", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/policies-envelope" + "$ref": "#/components/schemas/errors" } } } @@ -9174,38 +8892,48 @@ } } }, - "/policy-checks/{id}": { - "get": { - "operationId": "getPolicyCheck", - "summary": "Show a Policy Check", - "description": "Get information about a specific policy check.", + "/workspaces/{workspace_id}/relationships/ssh-key": { + "patch": { + "operationId": "assignWorkspaceSshKey", + "summary": "Assign an SSH Key to a Workspace", + "description": "Assign an SSH key to a workspace for use when cloning VCS repositories. Pass null for the id to unassign the current SSH key.\n", "tags": [ - "policy-checks" + "workspaces" ], "parameters": [ { "in": "path", - "name": "id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy check to show." + "description": "The external ID of the workspace." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/ssh-keys-nullable-identifier-document" + } + } + } + }, "responses": { "200": { - "description": "Policy check details", + "description": "SSH key assignment updated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/policy-checks-envelope" + "$ref": "#/components/schemas/workspaces-envelope" } } } }, - "default": { - "description": "Error details", + "404": { + "description": "Workspace or SSH key not found, or user unauthorized", "content": { "application/vnd.api+json": { "schema": { @@ -9213,40 +8941,6 @@ } } } - } - } - } - }, - "/policy-checks/{id}/output": { - "get": { - "operationId": "getPolicyCheckOutput", - "summary": "Get Policy Check Output", - "description": "Retrieve the Sentinel output log for a policy check. When output is available, the response redirects to a temporary presigned URL. When no result exists yet, the response is 204 No Content.", - "tags": [ - "policy-checks" - ], - "parameters": [ - { - "in": "path", - "name": "id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the policy check." - } - ], - "responses": { - "200": { - "description": "Output log retrieved successfully.", - "content": { - "application/octet-stream": { - "schema": { - "type": "string", - "format": "binary" - } - } - } }, "default": { "description": "Error details", @@ -9261,48 +8955,61 @@ } } }, - "/policy-checks/{id}/actions/override": { - "post": { - "operationId": "overridePolicyCheck", - "summary": "Override a Policy Check", - "description": "Override a soft-mandatory or warning policy check to allow the run to continue.", + "/workspaces/{workspace_id}/relationships/vars": { + "patch": { + "operationId": "updateWorkspaceVars", + "summary": "Update Workspace Variables", + "description": "Batch update workspace variables. Provide an array of variable objects to update. Variables are matched by their external ID.\n", "tags": [ - "policy-checks" + "workspaces" ], "parameters": [ { "in": "path", - "name": "id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy check to override." + "description": "The external ID of the workspace." } ], "requestBody": { - "required": false, + "required": true, "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/action-comment" + "$ref": "#/components/schemas/workspace-vars-update-document" } } } }, "responses": { - "200": { - "description": "Policy check successfully overridden", + "204": { + "description": "Variables updated" + }, + "400": { + "description": "Too many variables or invalid request", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/policy-checks-envelope" + "$ref": "#/components/schemas/errors" } } } }, - "409": { - "description": "The policy check is not in an overridable state.", + "404": { + "description": "Workspace not found or user unauthorized to update variables", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Validation error on one or more variables", "content": { "application/vnd.api+json": { "schema": { @@ -9324,57 +9031,42 @@ } } }, - "/runs/{run_id}/policy-checks": { + "/workspaces/{workspace_id}/relationships/tag-bindings": { "get": { - "operationId": "listRunPolicyChecks", - "summary": "List Policy Checks for a Run", - "description": "List the policy checks associated with a run.", + "operationId": "listWorkspaceTagBindings", + "summary": "List Workspace Tags", + "description": "List all tags associated with a workspace.", "tags": [ - "policy-checks" + "workspaces" ], "parameters": [ { "in": "path", - "name": "run_id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the run to list policy checks for." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "The ID of the workspace." } ], "responses": { "200": { - "description": "List of policy checks", + "description": "List of tags", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/policy-checks" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } + "$ref": "#/components/schemas/tag-bindings-collection" + } + } + } + }, + "404": { + "description": "Workspace not found or user unauthorized to view workspace", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -9390,62 +9082,45 @@ } } } - } - }, - "/policy-sets/{policy_set_id}/parameters": { - "get": { - "operationId": "listPolicySetParams", - "summary": "List Policy Set Parameters", - "description": "List parameters belonging to a policy set.", - "tags": [ - "policy-set-params" - ], + }, + "post": { + "operationId": "addWorkspaceTagBindings", + "summary": "Add Tag Bindings to a Workspace", + "description": "Add one or more tag bindings to a workspace.", + "tags": [ + "workspaces" + ], "parameters": [ { "in": "path", - "name": "policy_set_id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy set." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "The external ID of the workspace." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/tag-bindings-collection" + } + } + } + }, "responses": { - "200": { - "description": "List of policy set parameters", + "204": { + "description": "Tags added" + }, + "404": { + "description": "Workspace not found or user unauthorized to manage tags", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/vars" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } + "$ref": "#/components/schemas/errors" } } } @@ -9462,22 +9137,22 @@ } } }, - "post": { - "operationId": "createPolicySetParam", - "summary": "Create a Policy Set Parameter", - "description": "Create a new parameter for a policy set.", + "patch": { + "operationId": "replaceWorkspaceTagBindings", + "summary": "Replace Tag Bindings in a Workspace", + "description": "Replace all tag bindings in a workspace.", "tags": [ - "policy-set-params" + "workspaces" ], "parameters": [ { "in": "path", - "name": "policy_set_id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy set." + "description": "The ID of the workspace." } ], "requestBody": { @@ -9485,18 +9160,21 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/tag-bindings-collection" } } } }, "responses": { - "201": { - "description": "Policy set parameter created", + "204": { + "description": "Tag bindings replaced" + }, + "404": { + "description": "Workspace not found or user unauthorized to manage tag bindings", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/errors" } } } @@ -9514,41 +9192,72 @@ } } }, - "/policy-sets/{policy_set_id}/parameters/{id}": { + "/workspaces/{workspace_id}/relationships/tags": { "get": { - "operationId": "getPolicySetParam", - "summary": "Get a Policy Set Parameter", - "description": "Get details about a policy set parameter.", + "operationId": "listWorkspaceTags", + "summary": "List Workspace Tags", + "description": "List all tags associated with a workspace.", "tags": [ - "policy-set-params" + "workspaces" ], "parameters": [ { "in": "path", - "name": "policy_set_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the policy set." - }, - { - "in": "path", - "name": "id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the parameter." + "description": "The external ID of the workspace." } ], "responses": { "200": { - "description": "Policy set parameter details", + "description": "List of tags", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "tags" + ] + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Workspace not found or user unauthorized to view workspace", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -9565,31 +9274,22 @@ } } }, - "patch": { - "operationId": "updatePolicySetParam", - "summary": "Update a Policy Set Parameter", - "description": "Update an existing policy set parameter.", + "post": { + "operationId": "addWorkspaceTags", + "summary": "Add Tags to a Workspace", + "description": "Add one or more tags to a workspace.", "tags": [ - "policy-set-params" + "workspaces" ], "parameters": [ { "in": "path", - "name": "policy_set_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the policy set." - }, - { - "in": "path", - "name": "id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the parameter to update." + "description": "The external ID of the workspace." } ], "requestBody": { @@ -9597,18 +9297,21 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/tags-create-array-document" } } } }, "responses": { - "200": { - "description": "Policy set parameter updated", + "204": { + "description": "Tags added" + }, + "404": { + "description": "Workspace not found or user unauthorized to manage tags", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vars-envelope" + "$ref": "#/components/schemas/errors" } } } @@ -9626,35 +9329,46 @@ } }, "delete": { - "operationId": "deletePolicySetParam", - "summary": "Delete a Policy Set Parameter", - "description": "Delete a policy set parameter.", + "operationId": "removeWorkspaceTags", + "summary": "Remove Tags from a Workspace", + "description": "Remove one or more tags from a workspace.", "tags": [ - "policy-set-params" + "workspaces" ], "parameters": [ { "in": "path", - "name": "policy_set_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the policy set." - }, - { - "in": "path", - "name": "id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the parameter to delete." + "description": "The external ID of the workspace." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/tags-remove-array-document" + } + } + } + }, "responses": { "204": { - "description": "Policy set parameter deleted" + "description": "Tags removed" + }, + "404": { + "description": "Workspace not found or user unauthorized to manage tags", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } }, "default": { "description": "Error details", @@ -9669,32 +9383,46 @@ } } }, - "/policy-sets/{policy_set_id}": { + "/workspaces/{workspace_id}/relationships/data-retention-policy": { + "x-vis": [ + "tfe" + ], "get": { - "operationId": "getPolicySet", - "summary": "Get a Policy Set", - "description": "Get details about a specific policy set.", + "operationId": "getWorkspaceDataRetentionPolicy", + "summary": "Get Workspace Data Retention Policy", + "description": "Show the data retention policy explicitly set on the workspace.\n\nThis operation is only available in Terraform Enterprise.", "tags": [ - "policy-sets" + "workspaces", + "data-retention-policies" ], "parameters": [ { "in": "path", - "name": "policy_set_id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy set." + "description": "The external ID of the workspace." } ], "responses": { "200": { - "description": "Policy set details", + "description": "Workspace data retention policy", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/policy-sets-envelope" + "$ref": "#/components/schemas/data-retention-policy-envelope" + } + } + } + }, + "404": { + "description": "Workspace not found or policy not set", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -9712,21 +9440,22 @@ } }, "patch": { - "operationId": "updatePolicySet", - "summary": "Update a Policy Set", - "description": "Update an existing policy set.", + "operationId": "setWorkspaceDataRetentionPolicy", + "summary": "Set Workspace Data Retention Policy", + "description": "Create or update the data retention policy explicitly set on the workspace.\n\nThis operation is only available in Terraform Enterprise.", "tags": [ - "policy-sets" + "workspaces", + "data-retention-policies" ], "parameters": [ { "in": "path", - "name": "policy_set_id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy set." + "description": "The external ID of the workspace." } ], "requestBody": { @@ -9734,18 +9463,38 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/policy-sets-envelope" + "$ref": "#/components/schemas/data-retention-policy-envelope" } } } }, "responses": { "200": { - "description": "Policy set updated", + "description": "Data retention policy set", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/policy-sets-envelope" + "$ref": "#/components/schemas/data-retention-policy-envelope" + } + } + } + }, + "404": { + "description": "Workspace not found or user unauthorized", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Malformed request body", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -9763,26 +9512,37 @@ } }, "delete": { - "operationId": "deletePolicySet", - "summary": "Delete a Policy Set", - "description": "Delete a policy set. Deleting a policy set does not delete the policies it contains.", + "operationId": "deleteWorkspaceDataRetentionPolicy", + "summary": "Delete Workspace Data Retention Policy", + "description": "Remove the data retention policy explicitly set on the workspace.\n\nThis operation is only available in Terraform Enterprise.", "tags": [ - "policy-sets" + "workspaces", + "data-retention-policies" ], "parameters": [ { "in": "path", - "name": "policy_set_id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy set." + "description": "The external ID of the workspace." } ], "responses": { "204": { - "description": "Policy set deleted" + "description": "Data retention policy deleted" + }, + "404": { + "description": "Workspace not found or user unauthorized", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } }, "default": { "description": "Error details", @@ -9797,95 +9557,47 @@ } } }, - "/organizations/{organization_name}/policy-sets": { + "/workspaces/{workspace_id}/current-state-version": { "get": { - "operationId": "listPolicySets", - "summary": "List Policy Sets", - "description": "List all policy sets in an organization.", + "operationId": "getCurrentStateVersion", + "summary": "Get Current State Version", + "description": "Get the current state version for a workspace.", "tags": [ - "policy-sets" + "workspaces" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The name of the organization." - }, - { - "in": "query", - "name": "filter[versioned]", - "schema": { - "type": "boolean" - }, - "required": false, - "description": "If true, only return versioned policy sets. If false, only return non-versioned policy sets." - }, - { - "in": "query", - "name": "filter[kind]", - "schema": { - "type": "string", - "enum": [ - "sentinel", - "opa", - "tfpolicy" - ] - }, - "required": false, - "description": "Filter policy sets by kind." + "description": "The external ID of the workspace." }, { "in": "query", - "name": "search[name]", + "name": "include", "schema": { "type": "string" }, "required": false, - "description": "Filter policy sets by name." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "Optionally side-load relationships. For example, outputs or created-by.\n" } ], "responses": { "200": { - "description": "List of policy sets", + "description": "Current state version details", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/policy-sets" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } + "$ref": "#/components/schemas/current-state-version-envelope" } } } }, - "default": { - "description": "Error details", + "404": { + "description": "Workspace not found, no current state version exists, or user unauthorized", "content": { "application/vnd.api+json": { "schema": { @@ -9893,47 +9605,6 @@ } } } - } - } - }, - "post": { - "operationId": "createPolicySet", - "summary": "Create a Policy Set", - "description": "Create a new policy set in an organization.", - "tags": [ - "policy-sets" - ], - "parameters": [ - { - "in": "path", - "name": "organization_name", - "schema": { - "type": "string" - }, - "required": true, - "description": "The name of the organization." - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/policy-sets-envelope" - } - } - } - }, - "responses": { - "201": { - "description": "Policy set created", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/policy-sets-envelope" - } - } - } }, "default": { "description": "Error details", @@ -9948,41 +9619,38 @@ } } }, - "/policy-sets/{policy_set_id}/relationships/workspaces": { - "post": { - "operationId": "addPolicySetWorkspaces", - "summary": "Add Workspaces to a Policy Set", - "description": "Add workspaces to a policy set. Relationships are additive; existing workspace memberships are preserved.", + "/workspaces/{workspace_id}/current-assessment-result": { + "get": { + "operationId": "getCurrentAssessmentResult", + "summary": "Get Current Assessment Result", + "description": "Get the most recent drift detection assessment result for a workspace.", "tags": [ - "policy-sets" + "workspaces" ], "parameters": [ { "in": "path", - "name": "policy_set_id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy set." + "description": "The external ID of the workspace." } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-identifier-array-document" + "responses": { + "200": { + "description": "Current assessment result", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/assessment-results-envelope" + } } } - } - }, - "responses": { - "204": { - "description": "Workspaces successfully added to policy set." }, - "default": { - "description": "Error details", + "404": { + "description": "Workspace not found, no current assessment result exists, or user unauthorized", "content": { "application/vnd.api+json": { "schema": { @@ -9990,40 +9658,6 @@ } } } - } - } - }, - "delete": { - "operationId": "removePolicySetWorkspaces", - "summary": "Remove Workspaces from a Policy Set", - "description": "Remove workspaces from a policy set. Workspaces not currently in the set are ignored.", - "tags": [ - "policy-sets" - ], - "parameters": [ - { - "in": "path", - "name": "policy_set_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the policy set." - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-identifier-array-document" - } - } - } - }, - "responses": { - "204": { - "description": "Workspaces successfully removed from policy set." }, "default": { "description": "Error details", @@ -10038,131 +9672,129 @@ } } }, - "/policy-sets/{policy_set_id}/relationships/policies": { - "post": { - "operationId": "addPolicySetPolicies", - "summary": "Add Policies to a Policy Set", - "description": "Add policies to a policy set. Relationships are additive; existing policy memberships are preserved.", + "/workspaces/{workspace_id}/applicable-varsets": { + "get": { + "operationId": "listApplicableVarsets", + "summary": "List Applicable Variable Sets", + "description": "List the variable sets that can be applied to a workspace. This returns variable sets from the workspace's organization that are not already applied to the workspace, filtered by project scope.\n", "tags": [ - "policy-sets" + "workspaces" ], "parameters": [ { "in": "path", - "name": "policy_set_id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy set." - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/policies-identifier-array-document" - } - } - } - }, - "responses": { - "204": { - "description": "Policies successfully added to policy set." + "description": "The external ID of the workspace." }, - "default": { - "description": "Error details", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - } - } - }, - "delete": { - "operationId": "removePolicySetPolicies", - "summary": "Remove Policies from a Policy Set", - "description": "Remove policies from a policy set. Policies not currently in the set are ignored.", - "tags": [ - "policy-sets" - ], - "parameters": [ { - "in": "path", - "name": "policy_set_id", + "in": "query", + "name": "q", "schema": { "type": "string" }, - "required": true, - "description": "The ID of the policy set." + "required": false, + "description": "Optional search query to filter variable sets by name." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/policies-identifier-array-document" - } - } - } - }, "responses": { - "204": { - "description": "Policies successfully removed from policy set." - }, - "default": { - "description": "Error details", + "200": { + "description": "List of applicable variable sets", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "varsets" + ] + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "global": { + "type": "boolean" + }, + "auto-apply": { + "type": "boolean" + }, + "var-count": { + "type": "integer" + }, + "workspace-count": { + "type": "integer" + }, + "project-count": { + "type": "integer" + }, + "created-at": { + "type": "string", + "format": "date-time", + "readOnly": true + }, + "updated-at": { + "type": "string", + "format": "date-time", + "readOnly": true + } + } + } + } + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + }, + "status-counts": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } } } } - } - } - } - }, - "/policy-sets/{policy_set_id}/relationships/projects": { - "post": { - "operationId": "addPolicySetProjects", - "summary": "Add Projects to a Policy Set", - "description": "Add projects to a policy set. Relationships are additive; existing project memberships are preserved.", - "tags": [ - "policy-sets" - ], - "parameters": [ - { - "in": "path", - "name": "policy_set_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the policy set." - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/projects-identifier-array-document" - } - } - } - }, - "responses": { - "204": { - "description": "Projects successfully added to policy set." }, - "default": { - "description": "Error details", + "404": { + "description": "Workspace not found or user unauthorized to view workspace", "content": { "application/vnd.api+json": { "schema": { @@ -10170,40 +9802,6 @@ } } } - } - } - }, - "delete": { - "operationId": "removePolicySetProjects", - "summary": "Remove Projects from a Policy Set", - "description": "Remove projects from a policy set. Projects not currently in the set are ignored.", - "tags": [ - "policy-sets" - ], - "parameters": [ - { - "in": "path", - "name": "policy_set_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the policy set." - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/projects-identifier-array-document" - } - } - } - }, - "responses": { - "204": { - "description": "Projects successfully removed from policy set." }, "default": { "description": "Error details", @@ -10218,38 +9816,34 @@ } } }, - "/policy-sets/{policy_set_id}/relationships/workspace-exclusions": { + "/runs": { "post": { - "operationId": "addPolicySetWorkspaceExclusions", - "summary": "Add Workspace Exclusions to a Policy Set", - "description": "Add workspace exclusions to a policy set. Excluded workspaces will not have the policy set applied to them even if the set is global.", + "operationId": "createRun", + "summary": "Create a Run", + "description": "Create a new run.", "tags": [ - "policy-sets" - ], - "parameters": [ - { - "in": "path", - "name": "policy_set_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the policy set." - } + "runs" ], "requestBody": { "required": true, "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspaces-identifier-array-document" + "$ref": "#/components/schemas/runs-envelope" } } } }, "responses": { - "204": { - "description": "Workspace exclusions successfully added to policy set." + "201": { + "description": "Run created", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/runs-envelope" + } + } + } }, "default": { "description": "Error details", @@ -10263,158 +9857,49 @@ } } }, - "delete": { - "operationId": "removePolicySetWorkspaceExclusions", - "summary": "Remove Workspace Exclusions from a Policy Set", - "description": "Remove workspace exclusions from a policy set. Workspace exclusions not currently in the set are ignored.", + "get": { + "operationId": "listRuns", + "summary": "List Runs", + "description": "List all runs in a workspace.", "tags": [ - "policy-sets" + "runs" ], "parameters": [ { - "in": "path", - "name": "policy_set_id", + "in": "query", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy set." - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspaces-identifier-array-document" - } - } - } - }, - "responses": { - "204": { - "description": "Workspace exclusions successfully removed from policy set." + "description": "Workspace ID" }, - "default": { - "description": "Error details", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - } - } - } - }, - "/policy-sets/{policy_set_id}/relationships/project-exclusions": { - "post": { - "operationId": "addPolicySetProjectExclusions", - "summary": "Add Project Exclusions to a Policy Set", - "description": "Add project exclusions to a policy set. Excluded projects will not have the policy set applied to them even if the set is global.", - "tags": [ - "policy-sets" - ], - "parameters": [ { - "in": "path", - "name": "policy_set_id", + "in": "query", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy set." - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/projects-identifier-array-document" - } - } - } - }, - "responses": { - "204": { - "description": "Project exclusions successfully added to policy set." + "description": "Organization Name" }, - "default": { - "description": "Error details", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - } - } - }, - "delete": { - "operationId": "removePolicySetProjectExclusions", - "summary": "Remove Project Exclusions from a Policy Set", - "description": "Remove project exclusions from a policy set. project exclusions not currently in the set are ignored.", - "tags": [ - "policy-sets" - ], - "parameters": [ { - "in": "path", - "name": "policy_set_id", + "in": "query", + "name": "filter[operation]", "schema": { "type": "string" }, - "required": true, - "description": "The ID of the policy set." - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/projects-identifier-array-document" - } - } - } - }, - "responses": { - "204": { - "description": "Project exclusions successfully removed from policy set." + "required": false, + "description": "Filter by run operation." }, - "default": { - "description": "Error details", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - } - } - } - }, - "/policy-sets/{policy_set_id}/versions": { - "get": { - "operationId": "listPolicySetVersions", - "summary": "List Policy Set Versions", - "description": "List all versions of a policy set.", - "tags": [ - "policy-set-versions" - ], - "parameters": [ { - "in": "path", - "name": "policy_set_id", + "in": "query", + "name": "filter[status]", "schema": { "type": "string" }, - "required": true, - "description": "The ID of the policy set." + "required": false, + "description": "Filter by run status." }, { "$ref": "#/components/parameters/page_number" @@ -10425,7 +9910,7 @@ ], "responses": { "200": { - "description": "List of policy set versions", + "description": "List of runs", "content": { "application/vnd.api+json": { "schema": { @@ -10434,7 +9919,7 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/policy-set-versions" + "$ref": "#/components/schemas/runs" } }, "meta": { @@ -10464,32 +9949,43 @@ } } } - }, - "post": { - "operationId": "createPolicySetVersion", - "summary": "Create a Policy Set Version", - "description": "Create a new version for a policy set. The version will be in a pending state until policies are uploaded to it.", + } + }, + "/runs/{run_id}": { + "get": { + "operationId": "getRun", + "summary": "Get Run details", + "description": "Get details about a run.", "tags": [ - "policy-set-versions" + "runs" ], "parameters": [ { "in": "path", - "name": "policy_set_id", + "name": "run_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy set." + "description": "Run ID" + }, + { + "in": "query", + "name": "include", + "schema": { + "type": "string" + }, + "required": false, + "description": "Available side-load related resources. Multiple values can be comma-separated.\n\nAvailable includes:\n- `plan` - The plan for this run\n- `apply` - The apply for this run\n- `created_by` - The user who created this run\n- `configuration_version` - The configuration version used\n- `configuration_version.ingress_attributes` - VCS ingress details\n- `cost_estimate` - Cost estimation for this run\n- `workspace` - The workspace this run belongs to\n- `task_stages` - Run task stages\n- `tf_policy_evaluations` - Terraform Policy evaluations *(public-beta)*\n" } ], "responses": { - "201": { - "description": "Policy set version created", + "200": { + "description": "Run details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/policy-set-versions-envelope" + "$ref": "#/components/schemas/runs-envelope" } } } @@ -10507,32 +10003,32 @@ } } }, - "/policy-set-versions/{policy_set_version_id}": { + "/runs/{run_id}/configuration-version": { "get": { - "operationId": "getPolicySetVersion", - "summary": "Get a Policy Set Version", - "description": "Get details about a specific policy set version.", + "operationId": "getRunConfigurationVersion", + "summary": "Get Run Configuration Version", + "description": "Get details of a specific configuration version.", "tags": [ - "policy-set-versions" + "configuration-versions" ], "parameters": [ { "in": "path", - "name": "policy_set_version_id", + "name": "run_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy set version." + "description": "The ID of the run" } ], "responses": { "200": { - "description": "Policy set version details", + "description": "Configuration version details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/policy-set-versions-envelope" + "$ref": "#/components/schemas/configuration-versions-envelope" } } } @@ -10550,32 +10046,33 @@ } } }, - "/policy-evaluations/{policy_evaluation_id}": { + "/runs/{run_id}/configuration-version/download": { "get": { - "operationId": "getPolicyEvaluation", - "summary": "Show a Policy Evaluation", - "description": "Get details about a specific policy evaluation.", + "operationId": "downloadRunConfigurationVersion", + "summary": "Download Run Configuration Version", + "description": "Generate a temporary URL to download the configuration version files.", "tags": [ - "policy-evaluations" + "configuration-versions" ], "parameters": [ { "in": "path", - "name": "policy_evaluation_id", + "name": "run_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy evaluation to show." + "description": "The ID of the run." } ], "responses": { "200": { - "description": "Policy evaluation details", + "description": ".tar.gz file containing the configuration version.", "content": { - "application/vnd.api+json": { + "application/octet-stream": { "schema": { - "$ref": "#/components/schemas/policy-evaluations-envelope" + "type": "string", + "format": "binary" } } } @@ -10593,23 +10090,23 @@ } } }, - "/policy-evaluations/{policy_evaluation_id}/policy-set-outcomes": { + "/runs/{run_id}/comments": { "get": { - "operationId": "listPolicySetOutcomes", - "summary": "List Policy Set Outcomes", - "description": "List the policy set outcomes associated with a policy evaluation.", + "operationId": "listRunComments", + "summary": "List Comments for a Run", + "description": "List all comments for a run.", "tags": [ - "policy-evaluations" + "comments" ], "parameters": [ { "in": "path", - "name": "policy_evaluation_id", + "name": "run_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy evaluation to list outcomes for." + "description": "Run ID" }, { "$ref": "#/components/parameters/page_number" @@ -10620,7 +10117,7 @@ ], "responses": { "200": { - "description": "List of policy set outcomes", + "description": "List of comments", "content": { "application/vnd.api+json": { "schema": { @@ -10629,7 +10126,7 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/policy-set-outcomes" + "$ref": "#/components/schemas/comments" } }, "meta": { @@ -10659,34 +10156,42 @@ } } } - } - }, - "/policy-set-outcomes/{policy_set_outcome_id}": { - "get": { - "operationId": "getPolicySetOutcome", - "summary": "Show a Policy Set Outcome", - "description": "Get details about a specific policy set outcome.", + }, + "post": { + "operationId": "createRunComment", + "summary": "Create a Comment", + "description": "Create a new comment on a run.", "tags": [ - "policy-evaluations" + "comments" ], "parameters": [ { "in": "path", - "name": "policy_set_outcome_id", + "name": "run_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the policy set outcome to show." + "description": "Run ID" } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/comments-envelope" + } + } + } + }, "responses": { - "200": { - "description": "Policy set outcome details", + "201": { + "description": "Comment created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/policy-set-outcomes-envelope" + "$ref": "#/components/schemas/comments-envelope" } } } @@ -10704,57 +10209,32 @@ } } }, - "/task-stages/{task_stage_id}/policy-evaluations": { + "/comments/{id}": { "get": { - "operationId": "listTaskStagePolicyEvaluations", - "summary": "List Policy Evaluations for a Task Stage", - "description": "List the policy evaluations associated with a task stage.", + "operationId": "showComment", + "summary": "Show a Comment", + "description": "Get details about a comment.", "tags": [ - "policy-evaluations" + "comments" ], "parameters": [ { "in": "path", - "name": "task_stage_id", + "name": "id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the task stage to list policy evaluations for." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "Comment ID" } ], "responses": { "200": { - "description": "List of policy evaluations", + "description": "Comment details", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/policy-evaluations" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } + "$ref": "#/components/schemas/comments-envelope" } } } @@ -10772,37 +10252,51 @@ } } }, - "/plan-exports": { + "/runs/{run_id}/actions/apply": { "post": { - "operationId": "createPlanExport", - "summary": "Create a Plan Export", - "description": "Export data from a plan in the specified format. The export process is asynchronous, and the resulting data becomes downloadable when its status is \"finished\".", + "operationId": "applyRun", + "summary": "Apply a Run", + "description": "Apply a run that is paused waiting for confirmation.", "tags": [ - "plan-exports" + "runs" + ], + "parameters": [ + { + "in": "path", + "name": "run_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "Run ID" + } ], "requestBody": { - "required": true, + "required": false, "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/plan-exports-envelope" + "$ref": "#/components/schemas/action-comment" } } } }, "responses": { - "201": { - "description": "Plan export created", + "202": { + "description": "Successfully queued an apply request", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/plan-exports-envelope" + "type": "string", + "enum": [ + "null" + ] } } } }, - "default": { - "description": "Error details", + "409": { + "description": "Run was not paused for confirmation; apply not allowed.", "content": { "application/vnd.api+json": { "schema": { @@ -10814,32 +10308,75 @@ } } }, - "/plan-exports/{id}": { + "/workspaces/{workspace_id}/runs": { "get": { - "operationId": "showPlanExport", - "summary": "Show a Plan Export", - "description": "Get details about a specific plan export.", + "operationId": "listWorkspaceRuns", + "summary": "List Runs in a Workspace", + "description": "List all runs in a workspace.", "tags": [ - "plan-exports" + "runs" ], "parameters": [ { "in": "path", - "name": "id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the plan export to show." + "description": "Workspace ID" + }, + { + "in": "query", + "name": "filter[operation]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Filter by run operation." + }, + { + "in": "query", + "name": "filter[status]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Filter by run status." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" } ], "responses": { "200": { - "description": "Plan export details", + "description": "List of runs", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/plan-exports-envelope" + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/runs" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } } } } @@ -10855,28 +10392,75 @@ } } } - }, - "delete": { - "operationId": "deletePlanExport", - "summary": "Delete a Plan Export", - "description": "Delete the exported plan data. Plan exports expire after one hour, but can be deleted manually.", + } + }, + "/workspaces/{workspace_id}/run-triggers": { + "get": { + "operationId": "listRunTriggers", + "summary": "List Run Triggers", + "description": "List all run triggers for a workspace.", "tags": [ - "plan-exports" + "run-triggers" ], "parameters": [ { "in": "path", - "name": "id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the plan export to delete." + "description": "Workspace ID" + }, + { + "in": "query", + "name": "filter[run-trigger][type]", + "schema": { + "type": "string", + "enum": [ + "inbound", + "outbound" + ] + }, + "required": true, + "description": "Filter by run trigger type (inbound or outbound)" + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" } ], "responses": { - "204": { - "description": "Plan export deleted successfully" + "200": { + "description": "List of run triggers", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/run-triggers" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } }, "default": { "description": "Error details", @@ -10889,35 +10473,42 @@ } } } - } - }, - "/plan-exports/{id}/download": { - "get": { - "operationId": "downloadPlanExport", - "summary": "Download exported plan data", - "description": "Generate a temporary URL to the location of the exported plan data in a .tar.gz archive, then redirect to that link.", + }, + "post": { + "operationId": "createRunTrigger", + "summary": "Create a Run Trigger", + "description": "Create a new run trigger for a workspace.", "tags": [ - "plan-exports" + "run-triggers" ], "parameters": [ { "in": "path", - "name": "id", + "name": "workspace_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the plan export to download." + "description": "Workspace ID" } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/run-triggers-envelope" + } + } + } + }, "responses": { - "302": { - "description": "Temporary download URL generated", - "headers": { - "Location": { - "description": "Storage URL to .tar.gz archive containing the exported plan data", + "201": { + "description": "Run trigger created", + "content": { + "application/vnd.api+json": { "schema": { - "type": "string" + "$ref": "#/components/schemas/run-triggers-envelope" } } } @@ -10935,37 +10526,38 @@ } } }, - "/assessment-results/{id}": { + "/run-triggers/{id}": { "get": { - "summary": "Show an assessment result", - "operationId": "getAssessmentResult", + "operationId": "showRunTrigger", + "summary": "Show a Run Trigger", + "description": "Get details about a run trigger.", "tags": [ - "assessment-results" + "run-triggers" ], "parameters": [ { - "name": "id", "in": "path", - "required": true, - "description": "The external ID of the assessment result to show.", + "name": "id", "schema": { "type": "string" - } + }, + "required": true, + "description": "Run Trigger ID" } ], "responses": { "200": { - "description": "The request was successful", + "description": "Run trigger details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/assessment-results-envelope" + "$ref": "#/components/schemas/run-triggers-envelope" } } } }, "default": { - "description": "Assessment result not found, or user unauthorized to perform action", + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -10975,46 +10567,121 @@ } } } - } - }, - "/assessment-results/{id}/json-output": { - "get": { - "operationId": "getAssessmentResultJSONOutput", - "summary": "Get the JSON assessment output", - "description": "This endpoint returns the JSON formatted assessment output.\nThis is only available when the assessment has succeeded and has JSON output data.\n", + }, + "delete": { + "operationId": "deleteRunTrigger", + "summary": "Delete a Run Trigger", + "description": "Delete a run trigger.", + "tags": [ + "run-triggers" + ], "parameters": [ { - "name": "id", "in": "path", - "description": "The external ID of the assessment result.", - "required": true, + "name": "id", "schema": { "type": "string" - } + }, + "required": true, + "description": "Run Trigger ID" } ], - "tags": [ - "assessment-results" - ], "responses": { - "200": { - "description": "Assessment result JSON output found and returned.", + "204": { + "description": "Run trigger deleted" + }, + "default": { + "description": "Error details", "content": { - "application/json": { + "application/vnd.api+json": { "schema": { - "type": "object", - "additionalProperties": true, - "description": "The JSON formatted assessment output with dynamic structure" + "$ref": "#/components/schemas/errors" } } } + } + } + } + }, + "/organizations/{organization_name}/runs": { + "get": { + "operationId": "listOrganizationRuns", + "summary": "List Runs in an Organization", + "description": "List all runs in an organization.", + "tags": [ + "runs" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "Organization name" }, - "404": { - "description": "Assessment result failed or JSON output is not available.", + { + "in": "query", + "name": "filter[operation]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Filter by run operation." + }, + { + "in": "query", + "name": "filter[status]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Filter by run status." + }, + { + "in": "query", + "name": "filter[timeframe]", + "schema": { + "type": "string", + "default": "year" + }, + "required": false, + "description": "Filter by timeframe. Must be a numeric year or \"year\" for the last 12 months (the default)." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of runs", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/runs" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination-without-totals" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } } } } @@ -11032,43 +10699,32 @@ } } }, - "/assessment-results/{id}/json-schema": { + "/plans/{id}": { "get": { - "operationId": "getAssessmentResultJSONSchema", - "summary": "Get the JSON schema", - "description": "This endpoint returns the JSON schema for the assessment result.\nThis is only available when the assessment has succeeded and has provider schemas.\n", "parameters": [ { "name": "id", "in": "path", - "description": "The external ID of the assessment result.", + "description": "The ID of the plan to show.", "required": true, "schema": { "type": "string" } } ], + "operationId": "showPlan", + "summary": "Show a plan", + "description": "This endpoint returns a specific plan by its ID.", "tags": [ - "assessment-results" + "plans" ], "responses": { "200": { - "description": "JSON schema found and returned.", - "content": { - "application/json": { - "schema": { - "type": "object", - "description": "The JSON schema of the assessment result" - } - } - } - }, - "404": { - "description": "Assessment result failed or JSON schema is not available.", + "description": "Successfully returned the plan.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/plans-envelope" } } } @@ -11086,16 +10742,16 @@ } } }, - "/assessment-results/{id}/sanitized-plan": { + "/plans/{id}/json-output": { "get": { - "operationId": "getAssessmentResultSanitizedPlan", - "summary": "Get the sanitized plan", - "description": "This endpoint returns the sanitized plan for the assessment result.\nThis is only available when HYOK is enabled for the organization,\nthe assessment has succeeded, and a sanitized plan is available.\n", + "operationId": "getPlanJSONOutput", + "summary": "Get the JSON execution plan", + "description": "This endpoint generates a temporary authenticated URL to the location of the JSON formatted execution plan.\nWhen successful, this endpoint responds with a temporary redirect that should be followed.\n\nThis endpoint is available for plans using Terraform 0.12 and later.\nThe temporary URL has a life of 1 minute and should not be relied upon beyond the initial request.\n", "parameters": [ { "name": "id", "in": "path", - "description": "The external ID of the assessment result.", + "description": "The ID of the plan to show.", "required": true, "schema": { "type": "string" @@ -11103,22 +10759,25 @@ } ], "tags": [ - "assessment-results" + "plans" ], "responses": { - "200": { - "description": "Sanitized plan found and returned.", - "content": { - "application/json": { + "204": { + "description": "Plan JSON supported, but plan has not yet completed." + }, + "307": { + "description": "Plan JSON found and temporary download URL generated.", + "headers": { + "Location": { + "description": "Temporary URL to download the JSON output", "schema": { - "type": "object", - "description": "The sanitized plan output" + "type": "string" } } } }, - "404": { - "description": "HYOK not available, assessment result failed, or sanitized plan is not available.", + "422": { + "description": "Plan does not use a supported version of Terraform (< 0.12.X).", "content": { "application/vnd.api+json": { "schema": { @@ -11140,60 +10799,62 @@ } } }, - "/assessment-results/{id}/log-output": { + "/plans/{id}/json-output-redacted": { "get": { - "operationId": "getAssessmentResultLogOutput", - "summary": "Get the log output", - "description": "This endpoint returns the log output for the assessment result.\nSupports both JSON and plain text formats based on the Accept header.\nQuery parameters allow for pagination of log output.\n", + "operationId": "getPlanJSONOutputRedacted", + "summary": "Get the redacted JSON execution plan", + "description": "This endpoint generates a temporary authenticated URL to the location of the redacted JSON formatted execution plan, or returns the parsed redacted plan inline when the pre-generated file is not yet available.\n\nThis endpoint is available for plans using Terraform 0.15.2 and later. The temporary URL has a life of 1 minute and should not be relied upon beyond the initial request.\n", "parameters": [ { "name": "id", "in": "path", - "description": "The external ID of the assessment result.", + "description": "The ID of the plan to show.", "required": true, "schema": { "type": "string" } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of bytes to return", - "required": false, - "schema": { - "type": "integer" - } - }, - { - "name": "offset", - "in": "query", - "description": "Byte offset to start reading from", - "required": false, - "schema": { - "type": "integer" - } - }, - { - "name": "tail", - "in": "query", - "description": "If true, return the last N bytes instead of the first N bytes", - "required": false, - "schema": { - "type": "boolean" - } } ], "tags": [ - "assessment-results" + "plans" ], "responses": { "200": { - "description": "Log output returned successfully.", + "description": "Plan JSON output rendered inline because the pre-generated redacted plan file is not yet available.", "content": { - "text/plain": { + "application/json": {} + } + }, + "204": { + "description": "Redacted plan JSON supported, but plan has not yet completed." + }, + "307": { + "description": "Redacted plan JSON found and temporary download URL generated.", + "headers": { + "Location": { + "description": "Temporary URL to download the redacted JSON output", "schema": { - "type": "string", - "description": "The log output in plain text format" + "type": "string" + } + } + } + }, + "404": { + "description": "Plan or redacted plan output not found.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Plan does not use a supported version of Terraform (< 0.15.2).", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -11211,37 +10872,62 @@ } } }, - "/applies/{id}": { + "/plans/{id}/json-schema": { "get": { - "summary": "Show an apply", - "operationId": "getApply", - "tags": [ - "applies" - ], + "operationId": "getPlanJSONSchema", + "summary": "Get the JSON provider schema for a plan", + "description": "This endpoint generates a temporary authenticated URL to the location of the JSON formatted provider schemas associated with a plan.\nWhen successful, this endpoint responds with a temporary redirect that should be followed.\n\nThis endpoint is available for plans using Terraform 0.12 and later. The temporary URL has a life of 1 minute and should not be relied upon beyond the initial request.\n", "parameters": [ { "name": "id", "in": "path", + "description": "The ID of the plan to show.", "required": true, - "description": "The ID of the apply to show.", "schema": { "type": "string" } } ], + "tags": [ + "plans" + ], "responses": { - "200": { - "description": "The request was successful", + "204": { + "description": "Provider schema JSON supported, but plan has not yet completed." + }, + "307": { + "description": "Provider schema JSON found and temporary download URL generated.", + "headers": { + "Location": { + "description": "Temporary URL to download the JSON provider schemas", + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Plan or provider schema output not found.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/applies-envelope" + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Plan does not use a supported version of Terraform (< 0.12.X).", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } }, "default": { - "description": "Apply not found, or user unauthorized to perform action", + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -11253,38 +10939,34 @@ } } }, - "/applies/{id}/errored-state": { - "get": { - "summary": "Recover a failed state upload after applying", - "operationId": "getApplyErroredState", + "/plans/{id}/actions/soft-delete-backing-data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "softDeletePlanBackingData", + "summary": "Soft Delete Plan Backing Data", + "description": "Mark the backing files associated with this plan for garbage collection. Terraform permanently deletes backing files after a set number of days unless the plan is restored.\n\nThis operation is only available in Terraform Enterprise.", "tags": [ - "applies" + "plans" ], "parameters": [ { - "name": "id", "in": "path", - "required": true, - "description": "The ID of the apply to recover state for.", + "name": "id", "schema": { "type": "string" - } + }, + "required": true, + "description": "The ID of the plan to mark for garbage collection." } ], "responses": { - "307": { - "description": "Errored state available and user is authorized to read it", - "headers": { - "Location": { - "description": "Storage URL to raw state file", - "schema": { - "type": "string" - } - } - } + "204": { + "description": "Plan backing data marked for garbage collection" }, "default": { - "description": "Apply not found, errored state not uploaded, or user unauthorized to perform action", + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -11296,37 +10978,34 @@ } } }, - "/cost-estimates/{id}": { - "get": { - "summary": "Show a cost estimate", - "operationId": "showCostEstimate", + "/plans/{id}/actions/restore-backing-data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "restorePlanBackingData", + "summary": "Restore Plan Backing Data", + "description": "Restore backing files associated with a plan that was previously marked for garbage collection. This restores the plan back to its finalized state.\n\nThis operation is only available in Terraform Enterprise.", "tags": [ - "cost-estimates" + "plans" ], "parameters": [ { - "name": "id", "in": "path", - "required": true, - "description": "The ID of the cost estimate to show.", + "name": "id", "schema": { "type": "string" - } + }, + "required": true, + "description": "The ID of the plan to restore." } ], "responses": { - "200": { - "description": "The request was successful", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/cost-estimates-envelope" - } - } - } + "204": { + "description": "Plan backing data restore initiated" }, "default": { - "description": "Cost estimate not found, or user unauthorized to perform action", + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -11338,75 +11017,85 @@ } } }, - "/state-versions": { - "get": { - "operationId": "listStateVersions", - "summary": "List State Versions for a Workspace", - "description": "List state versions for a workspace, filtered by organization and workspace name.", + "/plans/{id}/actions/permanently-delete-backing-data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "permanentlyDeletePlanBackingData", + "summary": "Permanently Delete Plan Backing Data", + "description": "Permanently delete the backing files associated with a plan that has been soft deleted. This action cannot be undone.\n\nThis operation is only available in Terraform Enterprise.", "tags": [ - "state-versions" + "plans" ], "parameters": [ { - "in": "query", - "name": "filter[workspace][name]", + "in": "path", + "name": "id", "schema": { "type": "string" }, "required": true, - "description": "The name of the workspace to list state versions for." + "description": "The ID of the plan to permanently delete backing data for." + } + ], + "responses": { + "204": { + "description": "Plan backing data permanently deleted" }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/runs/{id}/plan/json-schema": { + "get": { + "operationId": "getPlanJSONSchemaOutput", + "summary": "Get the JSON provider schema corresponding to a plan", + "description": "This endpoint generates a temporary authenticated URL to the location of the JSON formatted provider schema.\nWhen successful, this endpoint responds with a temporary redirect that should be followed.\n\nThis endpoint is available for plans using Terraform 0.12 and later.\nThe temporary URL has a life of 1 minute and should not be relied upon beyond the initial request.\n", + "parameters": [ { - "in": "query", - "name": "filter[organization][name]", - "schema": { - "type": "string" - }, + "name": "id", + "in": "path", + "description": "The ID of the plan to show.", "required": true, - "description": "The name of the organization that owns the workspace." - }, - { - "in": "query", - "name": "filter[status]", "schema": { "type": "string" - }, - "required": false, - "description": "Filter state versions by status. One or more comma-separated values from pending, finalized, or discarded." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + } } ], + "tags": [ + "plans" + ], "responses": { - "200": { - "description": "List of state versions", + "204": { + "description": "Plan JSON supported, but plan has not yet completed." + }, + "307": { + "description": "Plan JSON found and temporary download URL generated.", + "headers": { + "Location": { + "description": "Temporary URL to download the JSON schema output", + "schema": { + "type": "string" + } + } + } + }, + "422": { + "description": "Plan does not use a supported version of Terraform (< 0.12.X).", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/state-versions" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } + "$ref": "#/components/schemas/errors" } } } @@ -11424,32 +11113,32 @@ } } }, - "/state-versions/{state_version_id}": { + "/runs/{id}/plan": { "get": { - "operationId": "getStateVersion", - "summary": "Show a State Version", - "description": "Show details for a specific state version.", - "tags": [ - "state-versions" - ], "parameters": [ { + "name": "id", "in": "path", - "name": "state_version_id", + "description": "The ID of the run whose plan you want to get.", + "required": true, "schema": { "type": "string" - }, - "required": true, - "description": "The ID of the state version to show." + } } ], + "operationId": "getRunPlan", + "summary": "Get a plan by Run ID", + "description": "This endpoint returns a specific plan by its run ID.", + "tags": [ + "plans" + ], "responses": { "200": { - "description": "State version details", + "description": "Successfully returned the plan.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/state-versions-envelope" + "$ref": "#/components/schemas/plans-envelope" } } } @@ -11467,57 +11156,46 @@ } } }, - "/state-versions/{state_version_id}/outputs": { + "/runs/{id}/plan/json-output": { "get": { - "operationId": "listStateVersionOutputs", - "summary": "List State Version Outputs", - "description": "List the output values associated with a specific state version.", - "tags": [ - "state-versions" - ], + "operationId": "getRunPlanJsonOutput", + "summary": "Get the JSON execution plan by Run ID", + "description": "This endpoint generates a temporary authenticated URL to the location of the JSON formatted execution plan.\nWhen successful, this endpoint responds with a temporary redirect that should be followed.\n\nThis endpoint is available for plans using Terraform 0.12 and later.\nThe temporary URL has a life of 1 minute and should not be relied upon beyond the initial request.\n", "parameters": [ { + "name": "id", "in": "path", - "name": "state_version_id", + "description": "The ID of the run whose plan json you want to get.", + "required": true, "schema": { "type": "string" - }, - "required": true, - "description": "The ID of the state version whose outputs to list." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + } } ], + "tags": [ + "plans" + ], "responses": { - "200": { - "description": "List of state version outputs", - "content": { + "204": { + "description": "Plan JSON supported, but plan has not yet completed." + }, + "307": { + "description": "Plan JSON found and temporary download URL generated.", + "headers": { + "Location": { + "description": "Temporary URL to download the JSON output", + "schema": { + "type": "string" + } + } + } + }, + "422": { + "description": "Plan does not use a supported version of Terraform (< 0.12.X).", + "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/state-version-outputs" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } + "$ref": "#/components/schemas/errors" } } } @@ -11535,42 +11213,33 @@ } } }, - "/workspaces/{workspace_id}/state-versions": { - "post": { - "operationId": "createStateVersion", - "summary": "Create a State Version", - "description": "Create a state version and set it as the current state version for the given workspace. The workspace must be locked by the user creating the state version.", + "/policies/{policy_id}": { + "get": { + "operationId": "showPolicy", + "summary": "Show a Policy", + "description": "Get details about a policy.", "tags": [ - "state-versions" + "policies" ], "parameters": [ { + "name": "policy_id", "in": "path", - "name": "workspace_id", - "schema": { - "type": "string" - }, "required": true, - "description": "The ID of the workspace to create the state version in." - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/state-versions-envelope" - } + "description": "The ID of the policy to show.", + "schema": { + "type": "string", + "example": "pol-xxxxxxxxxxxxxxxx" } } - }, + ], "responses": { - "201": { - "description": "State version created", + "200": { + "description": "OK", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/state-versions-envelope" + "$ref": "#/components/schemas/policies-envelope" } } } @@ -11588,21 +11257,22 @@ } }, "patch": { - "operationId": "rollbackStateVersion", - "summary": "Rollback to a Previous State Version", - "description": "Create a state version by duplicating the specified state version and set it as the current state version for the given workspace. The workspace must be locked by the user performing the rollback.", + "operationId": "updatePolicy", + "summary": "Update a Policy", + "description": "Update the enforcement level or description of an existing policy. To update the policy code itself, use the upload endpoint.", "tags": [ - "state-versions" + "policies" ], "parameters": [ { + "name": "policy_id", "in": "path", - "name": "workspace_id", - "schema": { - "type": "string" - }, "required": true, - "description": "The ID of the workspace to rollback the state version in." + "description": "The ID of the policy to update.", + "schema": { + "type": "string", + "example": "pol-xxxxxxxxxxxxxxxx" + } } ], "requestBody": { @@ -11610,18 +11280,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/state-versions-envelope" + "$ref": "#/components/schemas/policies-envelope" } } } }, "responses": { - "201": { - "description": "State version rollback created", + "200": { + "description": "OK", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/state-versions-envelope" + "$ref": "#/components/schemas/policies-envelope" } } } @@ -11637,40 +11307,32 @@ } } } - } - }, - "/state-version-outputs/{state_version_output_id}": { - "get": { - "operationId": "getStateVersionOutput", - "summary": "Show a State Version Output", - "description": "Show details for a specific state version output.", + }, + "delete": { + "operationId": "deletePolicy", + "summary": "Delete a Policy", + "description": "Delete a policy from an organization.", "tags": [ - "state-version-outputs" + "policies" ], "parameters": [ { - "name": "state_version_output_id", + "name": "policy_id", "in": "path", "required": true, - "description": "The ID of the state version output to show.", + "description": "The ID of the policy to delete.", "schema": { - "type": "string" + "type": "string", + "example": "pol-xxxxxxxxxxxxxxxx" } } ], "responses": { - "200": { - "description": "The request was successful", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/state-version-outputs-envelope" - } - } - } + "204": { + "description": "No Content" }, "default": { - "description": "State version output not found or user not authorized to perform action", + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -11682,28 +11344,66 @@ } } }, - "/workspaces/{workspace_id}/current-state-version-outputs": { + "/organizations/{organization_name}/policies": { "get": { - "operationId": "getCurrentStateVersionOutputs", - "summary": "Show Current State Version Outputs for a Workspace", - "description": "List the current state version outputs for a workspace. Sensitive output values are not revealed and will be returned as null. Organization users who do not have permission to read state versions may use this endpoint to fetch the latest output values for a workspace.", + "operationId": "listPolicies", + "summary": "List Policies", + "description": "List all policies for an organization.", "tags": [ - "state-version-outputs" + "policies" ], "parameters": [ { - "name": "workspace_id", + "name": "organization_name", "in": "path", "required": true, - "description": "The ID of the workspace to read outputs from.", + "description": "The name of the organization.", + "schema": { + "type": "string", + "example": "my-organization" + } + }, + { + "name": "search[name]", + "in": "query", + "required": false, + "description": "Allows searching the organization's policies by name.", + "schema": { + "type": "string" + } + }, + { + "name": "filter[kind]", + "in": "query", + "required": false, + "description": "Filter policies by kind. Valid values are sentinel and opa.", + "schema": { + "type": "string", + "enum": [ + "sentinel", + "opa" + ] + } + }, + { + "name": "sort", + "in": "query", + "required": false, + "description": "Sort policies by the specified field. Valid values are name, -name, updated-at, and -updated-at. Prefix with - for descending order.", "schema": { "type": "string" } + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" } ], "responses": { "200": { - "description": "The request was successful", + "description": "OK", "content": { "application/vnd.api+json": { "schema": { @@ -11712,7 +11412,18 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/state-version-outputs" + "$ref": "#/components/schemas/policies" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } } } } @@ -11720,18 +11431,8 @@ } } }, - "503": { - "description": "State version outputs are being processed and are not yet ready. Retry the request.", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, "default": { - "description": "State version outputs not found or user not authorized to perform action", + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -11741,40 +11442,49 @@ } } } - } - }, - "/authentication-tokens/{id}": { - "get": { - "operationId": "getAuthenticationToken", - "summary": "Get authentication token details", - "description": "Get details about an authentication token", + }, + "post": { + "operationId": "createPolicy", + "summary": "Create a Policy", + "description": "Create a new policy object for the organization. After creation, upload the policy code using the upload endpoint.", "tags": [ - "authentication-tokens" + "policies" ], "parameters": [ { + "name": "organization_name", "in": "path", - "name": "id", - "schema": { - "type": "string" - }, "required": true, - "description": "ID - Can be a token ID or a team ID, depending on the token type" + "description": "The name of the organization.", + "schema": { + "type": "string", + "example": "my-organization" + } } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/policies-envelope" + } + } + } + }, "responses": { - "200": { - "description": "Authentication Token details", + "201": { + "description": "Created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/authentication-tokens-envelope" + "$ref": "#/components/schemas/policies-envelope" } } } }, "default": { - "description": "Error Details", + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -11784,57 +11494,92 @@ } } } - }, - "post": { - "operationId": "createAuthenticationToken", - "summary": "Create Authentication Token", - "description": "Create an authentication token", + } + }, + "/policies/{policy_id}/download": { + "get": { + "operationId": "downloadPolicy", + "summary": "Download a Policy", + "description": "Generate a temporary URL to the current version of the policy code and redirect to that location. Returns 404 if no policy code has been uploaded.", "tags": [ - "authentication-tokens" + "policies" ], "parameters": [ { + "name": "policy_id", "in": "path", - "name": "id", + "required": true, + "description": "The ID of the policy to download.", "schema": { - "type": "string" - }, + "type": "string", + "example": "pol-xxxxxxxxxxxxxxxx" + } + } + ], + "responses": { + "200": { + "description": ".tar.gz file containing the policy code.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/policies/{policy_id}/upload": { + "put": { + "operationId": "uploadPolicy", + "summary": "Upload a Policy", + "description": "Upload code to an existing Sentinel or OPA policy. The request body must be the policy code with a Content-Type of application/octet-stream. Policy uploads are limited to 10MB.", + "tags": [ + "policies" + ], + "parameters": [ + { + "name": "policy_id", + "in": "path", "required": true, - "description": "ID - Can be a token ID or a team ID, depending on the token type" + "description": "The ID of the policy to upload code to.", + "schema": { + "type": "string", + "example": "pol-xxxxxxxxxxxxxxxx" + } } ], "requestBody": { "required": true, "content": { - "application/vnd.api+json": { + "application/octet-stream": { "schema": { - "$ref": "#/components/schemas/authentication-tokens-envelope" + "type": "string", + "format": "binary", + "description": "The policy code as a binary stream." } } } }, "responses": { - "201": { - "description": "Authentication token created", + "200": { + "description": "OK", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/authentication-tokens" - } - ] - } - } - } + "$ref": "#/components/schemas/policies-envelope" } } } @@ -11850,13 +11595,15 @@ } } } - }, - "delete": { - "operationId": "deleteAuthenticationToken", - "summary": "Delete authentication Token", - "description": "Delete an authentication token", + } + }, + "/policy-checks/{id}": { + "get": { + "operationId": "getPolicyCheck", + "summary": "Show a Policy Check", + "description": "Get information about a specific policy check.", "tags": [ - "authentication-tokens" + "policy-checks" ], "parameters": [ { @@ -11866,12 +11613,19 @@ "type": "string" }, "required": true, - "description": "ID - Can be a token ID or a team ID, depending on the token type" + "description": "The ID of the policy check to show." } ], "responses": { - "204": { - "description": "Authentication token deleted" + "200": { + "description": "Policy check details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/policy-checks-envelope" + } + } + } }, "default": { "description": "Error details", @@ -11886,32 +11640,96 @@ } } }, - "/users/{user_id}": { + "/policy-checks/{id}/output": { "get": { - "operationId": "showUser", - "summary": "Show User", - "description": "Shows details for a given user.", + "operationId": "getPolicyCheckOutput", + "summary": "Get Policy Check Output", + "description": "Retrieve the Sentinel output log for a policy check. When output is available, the response redirects to a temporary presigned URL. When no result exists yet, the response is 204 No Content.", "tags": [ - "users" + "policy-checks" ], "parameters": [ { "in": "path", - "name": "user_id", + "name": "id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the desired user." + "description": "The ID of the policy check." } ], "responses": { "200": { - "description": "User details", + "description": "Output log retrieved successfully.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/users-envelope" + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/policy-checks/{id}/actions/override": { + "post": { + "operationId": "overridePolicyCheck", + "summary": "Override a Policy Check", + "description": "Override a soft-mandatory or warning policy check to allow the run to continue.", + "tags": [ + "policy-checks" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the policy check to override." + } + ], + "requestBody": { + "required": false, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/action-comment" + } + } + } + }, + "responses": { + "200": { + "description": "Policy check successfully overridden", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/policy-checks-envelope" + } + } + } + }, + "409": { + "description": "The policy check is not in an overridable state.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -11929,23 +11747,23 @@ } } }, - "/users/{user_id}/github-app-oauth-tokens": { + "/runs/{run_id}/policy-checks": { "get": { - "operationId": "listUserGithubAppOauthTokens", - "summary": "List User GitHub App OAuth Tokens", - "description": "List GitHub App OAuth tokens for a given user.", + "operationId": "listRunPolicyChecks", + "summary": "List Policy Checks for a Run", + "description": "List the policy checks associated with a run.", "tags": [ - "users" + "policy-checks" ], "parameters": [ { "in": "path", - "name": "user_id", + "name": "run_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the user." + "description": "The ID of the run to list policy checks for." }, { "$ref": "#/components/parameters/page_number" @@ -11956,7 +11774,7 @@ ], "responses": { "200": { - "description": "GitHub App OAuth tokens", + "description": "List of policy checks", "content": { "application/vnd.api+json": { "schema": { @@ -11965,12 +11783,9 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/github-app-oauth-tokens" + "$ref": "#/components/schemas/policy-checks" } }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, "meta": { "type": "object", "properties": { @@ -11978,6 +11793,9 @@ "$ref": "#/components/schemas/pagination" } } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" } } } @@ -11997,23 +11815,26 @@ } } }, - "/users/{user_id}/authentication-tokens": { + "/runs/{run_id}/tf-policy-evaluations": { + "x-vis": [ + "public-beta" + ], "get": { - "operationId": "listUserTokens", - "summary": "List User Tokens", - "description": "List all tokens for a specified user", + "operationId": "listRunTfPolicyEvaluations", + "summary": "List Terraform Policy Evaluations for a Run", + "description": "List the Terraform Policy evaluations associated with a run.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "authentication-tokens" + "tf-policy-evaluations" ], "parameters": [ { "in": "path", - "name": "user_id", + "name": "run_id", "schema": { "type": "string" }, "required": true, - "description": "User ID" + "description": "The ID of the run to list Terraform Policy evaluations for." }, { "$ref": "#/components/parameters/page_number" @@ -12024,7 +11845,7 @@ ], "responses": { "200": { - "description": "Success", + "description": "List of Terraform Policy evaluations", "content": { "application/vnd.api+json": { "schema": { @@ -12033,12 +11854,9 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/authentication-tokens" + "$ref": "#/components/schemas/tf-policy-evaluation" } }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, "meta": { "type": "object", "properties": { @@ -12046,6 +11864,9 @@ "$ref": "#/components/schemas/pagination" } } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" } } } @@ -12063,110 +11884,65 @@ } } } - }, - "post": { - "operationId": "createUserToken", - "summary": "Create User Token", - "description": "Create a user token", - "tags": [ - "authentication-tokens" - ], - "parameters": [ - { - "in": "path", - "name": "user_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "User ID" - } - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/authentication-tokens-envelope" - } - } - } - }, - "responses": { - "201": { - "description": "User token created", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/authentication-tokens-envelope" - } - } - } - }, - "default": { - "description": "Error details", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - } - } } }, - "/agent-pools/{agent_pool_id}/authentication-tokens": { + "/tf-policy-evaluations/{id}": { + "x-vis": [ + "public-beta" + ], "get": { - "operationId": "listAgentTokens", - "summary": "List Agent Tokens", - "description": "List all tokens for the specified agent pool.", + "operationId": "getTfPolicyEvaluation", + "summary": "Show a Terraform Policy Evaluation", + "description": "Get details about a specific Terraform Policy evaluation.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "authentication-tokens" + "tf-policy-evaluations" ], "parameters": [ { "in": "path", - "name": "agent_pool_id", + "name": "id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the Agent Pool" - }, - { - "$ref": "#/components/parameters/page_number" + "description": "The ID of the Terraform Policy evaluation to show." }, { - "$ref": "#/components/parameters/page_size" + "in": "query", + "name": "include", + "schema": { + "type": "string" + }, + "required": false, + "description": "Comma-separated list of related resources to include. Valid values are `tf_policy_set_outcomes`." } ], "responses": { "200": { - "description": "Success", + "description": "Terraform Policy evaluation details", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/authentication-tokens" - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" + "allOf": [ + { + "$ref": "#/components/schemas/tf-policy-evaluations-envelope" }, - "meta": { + { "type": "object", "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" + "included": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/tf-policy-set-outcome" + } + ] + } } } } - } + ] } } } @@ -12182,48 +11958,60 @@ } } } - }, + } + }, + "/tf-policy-evaluations/{id}/actions/override": { + "x-vis": [ + "public-beta" + ], "post": { - "operationId": "createAgentToken", - "summary": "Create Agent Token", - "description": "Create an agent token", + "operationId": "overrideTfPolicyEvaluation", + "summary": "Override a Terraform Policy Evaluation", + "description": "Override a mandatory-overridable Terraform Policy evaluation to allow the run to continue.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "authentication-tokens" + "tf-policy-evaluations" ], "parameters": [ { "in": "path", - "name": "agent_pool_id", + "name": "id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the Agent Pool" + "description": "The ID of the Terraform Policy evaluation to override." } ], "requestBody": { - "required": true, + "required": false, "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/authentication-tokens-envelope" + "type": "object", + "properties": { + "comment": { + "type": "string", + "nullable": true, + "description": "An optional comment explaining the reason for overriding the Terraform Policy evaluation." + } + } } } } }, "responses": { - "201": { - "description": "Agent token created", + "200": { + "description": "Terraform Policy evaluation successfully overridden", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/authentication-tokens-envelope" + "$ref": "#/components/schemas/tf-policy-evaluations-envelope" } } } }, - "404": { - "description": "Agent Pool not found or user unauthorized to perform action", + "409": { + "description": "The Terraform Policy evaluation is not in an overridable state.", "content": { "application/vnd.api+json": { "schema": { @@ -12232,8 +12020,8 @@ } } }, - "422": { - "description": "Malformed request body (missing attributes, wrong types, etc.)", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -12241,9 +12029,105 @@ } } } + } + } + } + }, + "/tf-policy-evaluations/{tf_policy_evaluation_id}/tf-policy-set-outcomes": { + "x-vis": [ + "public-beta" + ], + "get": { + "operationId": "listTfPolicyEvaluationTfPolicySetOutcomes", + "summary": "List Terraform Policy Set Outcomes for a Terraform Policy Evaluation", + "description": "List the Terraform Policy set outcomes associated with a Terraform Policy evaluation. Supports filtering via the `filter` parameter.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", + "tags": [ + "tf-policy-evaluations" + ], + "parameters": [ + { + "in": "path", + "name": "tf_policy_evaluation_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the Terraform Policy evaluation to list Terraform Policy set outcomes for." + }, + { + "in": "query", + "name": "filter", + "style": "deepObject", + "explode": true, + "required": false, + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "passed", + "failed", + "errored", + "unknown" + ], + "description": "Filter outcomes by status." + }, + "enforcement_level": { + "type": "string", + "enum": [ + "advisory", + "mandatory", + "mandatory_overridable" + ], + "description": "Filter outcomes by enforcement level." + } + } + } + }, + "description": "Filter outcomes using OR-grouped AND conditions. Each numeric index defines\nan independent AND-condition group; groups are combined with OR.\n\nExample — return outcomes that are errored OR (failed + mandatory) OR (failed + mandatory_overridable):\n```\nfilter[0][status]=errored\n&filter[1][status]=failed&filter[1][enforcement_level]=mandatory\n&filter[2][status]=failed&filter[2][enforcement_level]=mandatory_overridable\n```\n" + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of Terraform Policy set outcomes", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/tf-policy-set-outcome" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } }, - "500": { - "description": "Failure during Agent Token creation", + "400": { + "description": "Invalid filter provided", "content": { "application/vnd.api+json": { "schema": { @@ -12265,13 +12149,16 @@ } } }, - "/teams/{id}/authentication-token": { + "/tf-policy-set-outcomes/{id}": { + "x-vis": [ + "public-beta" + ], "get": { - "operationId": "getAuthenticationToken", - "summary": "Get authentication token details", - "description": "Get details about an authentication token", + "operationId": "getTfPolicySetOutcome", + "summary": "Show a Terraform Policy Set Outcome", + "description": "Get details about a specific Terraform Policy set outcome.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "authentication-tokens" + "tf-policy-evaluations" ], "parameters": [ { @@ -12281,22 +12168,22 @@ "type": "string" }, "required": true, - "description": "ID - Can be a token ID or a team ID, depending on the token type" + "description": "The ID of the Terraform Policy set outcome to show." } ], "responses": { "200": { - "description": "Authentication Token details", + "description": "Terraform Policy set outcome details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/authentication-tokens-envelope" + "$ref": "#/components/schemas/tf-policy-set-outcomes-envelope" } } } }, "default": { - "description": "Error Details", + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -12306,38 +12193,36 @@ } } } - }, - "post": { - "operationId": "createAuthenticationToken", - "summary": "Create Authentication Token", - "description": "Create an authentication token", + } + }, + "/policy-sets/{policy_set_id}/parameters": { + "get": { + "operationId": "listPolicySetParams", + "summary": "List Policy Set Parameters", + "description": "List parameters belonging to a policy set.", "tags": [ - "authentication-tokens" + "policy-set-params" ], "parameters": [ { "in": "path", - "name": "id", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "ID - Can be a token ID or a team ID, depending on the token type" + "description": "The ID of the policy set." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/authentication-tokens-envelope" - } - } - } - }, "responses": { - "201": { - "description": "Authentication token created", + "200": { + "description": "List of policy set parameters", "content": { "application/vnd.api+json": { "schema": { @@ -12349,15 +12234,22 @@ "data": { "type": "array", "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/authentication-tokens" - } - ] + "$ref": "#/components/schemas/vars" } - } - } - } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } } } }, @@ -12373,27 +12265,44 @@ } } }, - "delete": { - "operationId": "deleteAuthenticationToken", - "summary": "Delete authentication Token", - "description": "Delete an authentication token", + "post": { + "operationId": "createPolicySetParam", + "summary": "Create a Policy Set Parameter", + "description": "Create a new parameter for a policy set.", "tags": [ - "authentication-tokens" + "policy-set-params" ], "parameters": [ { "in": "path", - "name": "id", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "ID - Can be a token ID or a team ID, depending on the token type" + "description": "The ID of the policy set." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/vars-envelope" + } + } + } + }, "responses": { - "204": { - "description": "Authentication token deleted" + "201": { + "description": "Policy set parameter created", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/vars-envelope" + } + } + } }, "default": { "description": "Error details", @@ -12408,164 +12317,49 @@ } } }, - "/organization/audit-trail": { - "x-vis": [ - "hcpt" - ], + "/policy-sets/{policy_set_id}/parameters/{id}": { "get": { - "operationId": "showOrganizationAuditTrail", - "summary": "List organization audit events", - "description": "Returns a list of audit events for the organization associated with the authentication token. HCP Terraform retains 14 days of audit log information. Unlike most HCP Terraform APIs, this endpoint does not use the JSON:API specification. This endpoint requires an organization token or an audit trail token; user tokens and team tokens are not accepted.", + "operationId": "getPolicySetParam", + "summary": "Get a Policy Set Parameter", + "description": "Get details about a policy set parameter.", "tags": [ - "audit-trails" + "policy-set-params" ], "parameters": [ { - "in": "query", - "name": "since", + "in": "path", + "name": "policy_set_id", "schema": { - "type": "string", - "format": "date-time" + "type": "string" }, - "required": false, - "description": "Returns only audit events created after this date. Must be a UTC ISO8601 datetime string (YYYY-MM-DDTHH:MM:SS.SSSZ)." - }, - { - "$ref": "#/components/parameters/page_number" + "required": true, + "description": "The ID of the policy set." }, { - "$ref": "#/components/parameters/page_size" + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the parameter." } ], "responses": { "200": { - "description": "Audit events list", + "description": "Policy set parameter details", "content": { - "application/json": { + "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "The ID of this audit event." - }, - "version": { - "type": "string", - "description": "The audit trail schema version." - }, - "type": { - "type": "string", - "description": "The type of audit event (defaults to \"Resource\")." - }, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "UTC ISO8601 timestamp of the event." - }, - "auth": { - "type": "object", - "properties": { - "accessor_id": { - "type": "string", - "description": "The ID of the audited actor." - }, - "description": { - "type": "string", - "nullable": true, - "description": "Username of the audited actor." - }, - "type": { - "type": "string", - "nullable": true, - "description": "Authentication type. One of \"Client\", \"Impersonated\", or \"System\"." - }, - "impersonator_id": { - "type": "string", - "nullable": true, - "description": "The ID of the impersonating actor, if available." - }, - "organization_id": { - "type": "string", - "description": "The ID of the organization." - } - } - }, - "request": { - "type": "object", - "properties": { - "id": { - "type": "string", - "nullable": true, - "description": "The ID of the request, if available." - } - } - }, - "resource": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "The ID of the audited resource." - }, - "type": { - "type": "string", - "description": "The type of the audited resource (e.g., \"run\")." - }, - "action": { - "type": "string", - "description": "The action that was audited (e.g., \"applied\")." - }, - "meta": { - "type": "object", - "nullable": true, - "additionalProperties": true, - "description": "Key-value metadata about the audited event. Defaults to null." - } - } - } - } - } - }, - "pagination": { - "type": "object", - "properties": { - "current_page": { - "type": "integer" - }, - "page_size": { - "type": "integer" - }, - "prev_page": { - "type": "integer", - "nullable": true - }, - "next_page": { - "type": "integer", - "nullable": true - }, - "total_pages": { - "type": "integer" - }, - "total_count": { - "type": "integer" - } - } - } - } + "$ref": "#/components/schemas/vars-envelope" } } } }, "default": { - "description": "Unauthorized or forbidden", + "description": "Error details", "content": { - "application/json": { + "application/vnd.api+json": { "schema": { "$ref": "#/components/schemas/errors" } @@ -12573,40 +12367,57 @@ } } } - } - }, - "/organizations/{organization_name}/authentication-token": { - "get": { - "operationId": "getOrganizationToken", - "summary": "Get organization token details", - "description": "Get details about an organization token", + }, + "patch": { + "operationId": "updatePolicySetParam", + "summary": "Update a Policy Set Parameter", + "description": "Update an existing policy set parameter.", "tags": [ - "authentication-tokens" + "policy-set-params" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "Organization name" + "description": "The ID of the policy set." + }, + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the parameter to update." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/vars-envelope" + } + } + } + }, "responses": { "200": { - "description": "Organization Token details", + "description": "Policy set parameter updated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/authentication-tokens-envelope" + "$ref": "#/components/schemas/vars-envelope" } } } }, "default": { - "description": "Error Details", + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -12617,41 +12428,76 @@ } } }, - "post": { - "operationId": "createOrganizationToken", - "summary": "Create Organization Token", - "description": "Create an organization token", - "tags": [ - "authentication-tokens" + "delete": { + "operationId": "deletePolicySetParam", + "summary": "Delete a Policy Set Parameter", + "description": "Delete a policy set parameter.", + "tags": [ + "policy-set-params" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "Organization name" + "description": "The ID of the policy set." + }, + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the parameter to delete." } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/authentication-tokens-envelope" + "responses": { + "204": { + "description": "Policy set parameter deleted" + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } } } } - }, + } + } + }, + "/policy-sets/{policy_set_id}": { + "get": { + "operationId": "getPolicySet", + "summary": "Get a Policy Set", + "description": "Get details about a specific policy set.", + "tags": [ + "policy-sets" + ], + "parameters": [ + { + "in": "path", + "name": "policy_set_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the policy set." + } + ], "responses": { - "201": { - "description": "Organization token created", + "200": { + "description": "Policy set details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/authentication-tokens-envelope" + "$ref": "#/components/schemas/policy-sets-envelope" } } } @@ -12668,27 +12514,44 @@ } } }, - "delete": { - "operationId": "deleteOrganizationToken", - "summary": "Delete organization Token", - "description": "Delete an organization token", + "patch": { + "operationId": "updatePolicySet", + "summary": "Update a Policy Set", + "description": "Update an existing policy set.", "tags": [ - "authentication-tokens" + "policy-sets" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "Organization name" + "description": "The ID of the policy set." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/policy-sets-envelope" + } + } + } + }, "responses": { - "204": { - "description": "Organization token deleted" + "200": { + "description": "Policy set updated", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/policy-sets-envelope" + } + } + } }, "default": { "description": "Error details", @@ -12701,62 +12564,28 @@ } } } - } - }, - "/organizations/{organization_name}/team-tokens": { - "get": { - "operationId": "listTeamTokensForAnOrganization", - "summary": "List Team Tokens for an Organization", - "description": "List all tokens for a specified organization", + }, + "delete": { + "operationId": "deletePolicySet", + "summary": "Delete a Policy Set", + "description": "Delete a policy set. Deleting a policy set does not delete the policies it contains.", "tags": [ - "authentication-tokens" + "policy-sets" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "Organization Name" - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "The ID of the policy set." } ], "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/authentication-tokens" - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - } - } - } - } - } + "204": { + "description": "Policy set deleted" }, "default": { "description": "Error details", @@ -12771,13 +12600,13 @@ } } }, - "/organizations/{organization_name}/teams": { + "/organizations/{organization_name}/policy-sets": { "get": { - "operationId": "listTeams", - "summary": "List Teams", - "description": "List teams in an organization. Any member of an organization can view visible teams and any secret teams they are a member of.", + "operationId": "listPolicySets", + "summary": "List Policy Sets", + "description": "List all policy sets in an organization.", "tags": [ - "teams" + "policy-sets" ], "parameters": [ { @@ -12787,38 +12616,39 @@ "type": "string" }, "required": true, - "description": "Name of the organization" + "description": "The name of the organization." }, { "in": "query", - "name": "q", + "name": "filter[versioned]", "schema": { - "type": "string" + "type": "boolean" }, "required": false, - "description": "A search query string. Teams are searchable by name (case-insensitive)." + "description": "If true, only return versioned policy sets. If false, only return non-versioned policy sets." }, { "in": "query", - "name": "filter[names]", + "name": "filter[kind]", "schema": { - "type": "string" + "type": "string", + "enum": [ + "sentinel", + "opa", + "tfpolicy" + ] }, "required": false, - "description": "If specified, restricts results to a team with a matching name. If multiple comma separated values are specified, teams matching any of the names are returned." + "description": "Filter policy sets by kind.\n\n**Note:** The following kind values are in public-beta:\n- `tfpolicy` - Terraform Policy enforcement\n" }, { "in": "query", - "name": "include", + "name": "search[name]", "schema": { - "type": "string", - "enum": [ - "users", - "organization-memberships" - ] + "type": "string" }, "required": false, - "description": "Optionally side-load relationships. Can include \"users\" or \"organization-memberships\"." + "description": "Filter policy sets by name." }, { "$ref": "#/components/parameters/page_number" @@ -12829,19 +12659,16 @@ ], "responses": { "200": { - "description": "Teams list", + "description": "List of policy sets", "content": { "application/vnd.api+json": { "schema": { "type": "object", - "required": [ - "data" - ], "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/teams" + "$ref": "#/components/schemas/policy-sets" } }, "meta": { @@ -12854,45 +12681,12 @@ }, "links": { "$ref": "#/components/schemas/self-with-pagination" - }, - "included": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/users" - }, - { - "$ref": "#/components/schemas/organization-memberships" - } - ] - } } } } } } }, - "400": { - "description": "Invalid include parameter", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "404": { - "description": "Organization not found, or user unauthorized to perform action", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, "default": { "description": "Error details", "content": { @@ -12906,11 +12700,11 @@ } }, "post": { - "operationId": "createTeam", - "summary": "Create Team", - "description": "Create a team in an organization.", + "operationId": "createPolicySet", + "summary": "Create a Policy Set", + "description": "Create a new policy set in an organization.", "tags": [ - "teams" + "policy-sets" ], "parameters": [ { @@ -12920,7 +12714,7 @@ "type": "string" }, "required": true, - "description": "Name of the organization" + "description": "The name of the organization." } ], "requestBody": { @@ -12928,54 +12722,24 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/teams-envelope" + "$ref": "#/components/schemas/policy-sets-envelope" } } } }, "responses": { - "200": { - "description": "Team created successfully", + "201": { + "description": "Policy set created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/teams-envelope" + "$ref": "#/components/schemas/policy-sets-envelope" } } } }, - "400": { - "description": "Invalid include parameter", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "404": { - "description": "Organization not found, or user unauthorized to perform action", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "422": { - "description": "Malformed request body (missing attributes, wrong types, etc.)", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "default": { - "description": "Error details", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -12987,90 +12751,38 @@ } } }, - "/teams/{team_id}": { - "get": { - "operationId": "getTeam", - "summary": "Show Team Information", - "description": "Get details about a team.", + "/policy-sets/{policy_set_id}/relationships/workspaces": { + "post": { + "operationId": "addPolicySetWorkspaces", + "summary": "Add Workspaces to a Policy Set", + "description": "Add workspaces to a policy set. Relationships are additive; existing workspace memberships are preserved.", "tags": [ - "teams" + "policy-sets" ], "parameters": [ { "in": "path", - "name": "team_id", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "Team ID" - }, - { - "in": "query", - "name": "include", - "schema": { - "type": "string", - "enum": [ - "users", - "organization-memberships" - ] - }, - "required": false, - "description": "Optionally side-load relationships. Can include \"users\" or \"organization-memberships\"." + "description": "The ID of the policy set." } ], - "responses": { - "200": { - "description": "Team details", - "content": { - "application/vnd.api+json": { - "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/teams-envelope" - }, - { - "type": "object", - "properties": { - "included": { - "type": "array", - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/users" - }, - { - "$ref": "#/components/schemas/organization-memberships" - } - ] - } - } - } - } - ] - } - } - } - }, - "400": { - "description": "Invalid include parameter", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "404": { - "description": "Team not found, or user unauthorized to perform action", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspaces-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Workspaces successfully added to policy set." }, "default": { "description": "Error details", @@ -13084,22 +12796,22 @@ } } }, - "patch": { - "operationId": "updateTeam", - "summary": "Update Team", - "description": "Update a team's attributes.", + "delete": { + "operationId": "removePolicySetWorkspaces", + "summary": "Remove Workspaces from a Policy Set", + "description": "Remove workspaces from a policy set. Workspaces not currently in the set are ignored.", "tags": [ - "teams" + "policy-sets" ], "parameters": [ { "in": "path", - "name": "team_id", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "Team ID" + "description": "The ID of the policy set." } ], "requestBody": { @@ -13107,34 +12819,17 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/teams-envelope" + "$ref": "#/components/schemas/workspaces-identifier-array-document" } } } }, "responses": { - "200": { - "description": "Team updated successfully", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/teams-envelope" - } - } - } - }, - "400": { - "description": "Invalid include parameter", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } + "204": { + "description": "Workspaces successfully removed from policy set." }, - "404": { - "description": "Team not found, or user unauthorized to perform action", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -13142,16 +12837,42 @@ } } } - }, - "422": { - "description": "Malformed request body (missing attributes, wrong types, etc.)", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } + } + } + } + }, + "/policy-sets/{policy_set_id}/relationships/policies": { + "post": { + "operationId": "addPolicySetPolicies", + "summary": "Add Policies to a Policy Set", + "description": "Add policies to a policy set. Relationships are additive; existing policy memberships are preserved.", + "tags": [ + "policy-sets" + ], + "parameters": [ + { + "in": "path", + "name": "policy_set_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the policy set." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/policies-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Policies successfully added to policy set." }, "default": { "description": "Error details", @@ -13166,36 +12887,36 @@ } }, "delete": { - "operationId": "deleteTeam", - "summary": "Delete Team", - "description": "Delete a team. Only organization owners can delete teams.", + "operationId": "removePolicySetPolicies", + "summary": "Remove Policies from a Policy Set", + "description": "Remove policies from a policy set. Policies not currently in the set are ignored.", "tags": [ - "teams" + "policy-sets" ], "parameters": [ { "in": "path", - "name": "team_id", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "Team ID" + "description": "The ID of the policy set." } ], - "responses": { - "204": { - "description": "Team deleted successfully" - }, - "404": { - "description": "Team not found, or user unauthorized to perform action", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/policies-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Policies successfully removed from policy set." }, "default": { "description": "Error details", @@ -13210,23 +12931,23 @@ } } }, - "/teams/{team_id}/relationships/users": { + "/policy-sets/{policy_set_id}/relationships/projects": { "post": { - "operationId": "addTeamMembersByUsername", - "summary": "Add Users to Team (by username)", - "description": "Add multiple users to a team using their usernames. Both users and teams must already exist.", + "operationId": "addPolicySetProjects", + "summary": "Add Projects to a Policy Set", + "description": "Add projects to a policy set. Relationships are additive; existing project memberships are preserved.", "tags": [ - "teams" + "policy-sets" ], "parameters": [ { "in": "path", - "name": "team_id", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the team." + "description": "The ID of the policy set." } ], "requestBody": { @@ -13234,44 +12955,14 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/users-identifier-array-document" + "$ref": "#/components/schemas/projects-identifier-array-document" } } } }, "responses": { "204": { - "description": "Users successfully added to team." - }, - "400": { - "description": "Invalid request (blank ID, wrong type, user does not exist, user is already a member, user is not in the organization).", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "403": { - "description": "Forbidden. The organization is managed by HCP.", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "404": { - "description": "Team not found, or user unauthorized to perform action.", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } + "description": "Projects successfully added to policy set." }, "default": { "description": "Error details", @@ -13286,21 +12977,21 @@ } }, "delete": { - "operationId": "removeTeamMembersByUsername", - "summary": "Remove Users from Team (by username)", - "description": "Remove multiple users from a team using their usernames. This only removes users from this team; it does not delete the users from the organization.", + "operationId": "removePolicySetProjects", + "summary": "Remove Projects from a Policy Set", + "description": "Remove projects from a policy set. Projects not currently in the set are ignored.", "tags": [ - "teams" + "policy-sets" ], "parameters": [ { "in": "path", - "name": "team_id", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the team." + "description": "The ID of the policy set." } ], "requestBody": { @@ -13308,44 +12999,14 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/users-identifier-array-document" + "$ref": "#/components/schemas/projects-identifier-array-document" } } } }, "responses": { "204": { - "description": "Users successfully removed from team." - }, - "400": { - "description": "Invalid request (blank ID, wrong type, user is not a member).", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "403": { - "description": "Forbidden. The organization is managed by HCP, or attempting to remove the last owner of the owners team.", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "404": { - "description": "Team not found, or user unauthorized to perform action.", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } + "description": "Projects successfully removed from policy set." }, "default": { "description": "Error details", @@ -13360,106 +13021,41 @@ } } }, - "/teams/{team_id}/relationships/organization-memberships": { - "get": { - "operationId": "listTeamOrganizationMemberships", - "summary": "List Team Organization Memberships", - "description": "List all organization memberships for a team. Returns both active members and invited users.", + "/policy-sets/{policy_set_id}/relationships/workspace-exclusions": { + "post": { + "operationId": "addPolicySetWorkspaceExclusions", + "summary": "Add Workspace Exclusions to a Policy Set", + "description": "Add workspace exclusions to a policy set. Excluded workspaces will not have the policy set applied to them even if the set is global.", "tags": [ - "teams" + "policy-sets" ], "parameters": [ { "in": "path", - "name": "team_id", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the team." - }, - { - "in": "query", - "name": "filter[status]", - "schema": { - "type": "string", - "enum": [ - "active", - "invited", - "inactive" - ] - }, - "required": false, - "description": "Filter memberships by status." - }, - { - "in": "query", - "name": "filter[is_service_account]", - "schema": { - "type": "string", - "enum": [ - "true", - "false" - ] - }, - "required": false, - "description": "Filter to include only service account members." - }, - { - "in": "query", - "name": "sort", - "schema": { - "type": "string", - "enum": [ - "status", - "-status" - ] - }, - "required": false, - "description": "Sort memberships. Prefix with '-' for descending order (e.g. '-status')." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "The ID of the policy set." } ], - "responses": { - "200": { - "description": "List of organization memberships for the team.", - "content": { - "application/vnd.api+json": { - "schema": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/organization-memberships" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } - } + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspaces-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Workspace exclusions successfully added to policy set." }, - "400": { - "description": "Invalid filter or sort parameter.", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -13467,16 +13063,40 @@ } } } - }, - "404": { - "description": "Team not found, or user unauthorized to perform action.", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } + } + } + }, + "delete": { + "operationId": "removePolicySetWorkspaceExclusions", + "summary": "Remove Workspace Exclusions from a Policy Set", + "description": "Remove workspace exclusions from a policy set. Workspace exclusions not currently in the set are ignored.", + "tags": [ + "policy-sets" + ], + "parameters": [ + { + "in": "path", + "name": "policy_set_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the policy set." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspaces-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Workspace exclusions successfully removed from policy set." }, "default": { "description": "Error details", @@ -13489,23 +13109,25 @@ } } } - }, + } + }, + "/policy-sets/{policy_set_id}/relationships/project-exclusions": { "post": { - "operationId": "addTeamMembersByOrgMembership", - "summary": "Add Users to Team (by organization membership ID)", - "description": "Add multiple users to a team using their organization membership IDs. Unlike the username method, users only need a pending invitation to the organization.", + "operationId": "addPolicySetProjectExclusions", + "summary": "Add Project Exclusions to a Policy Set", + "description": "Add project exclusions to a policy set. Excluded projects will not have the policy set applied to them even if the set is global.", "tags": [ - "teams" + "policy-sets" ], "parameters": [ { "in": "path", - "name": "team_id", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the team." + "description": "The ID of the policy set." } ], "requestBody": { @@ -13513,27 +13135,17 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/organization-memberships-identifier-array-document" + "$ref": "#/components/schemas/projects-identifier-array-document" } } } }, "responses": { "204": { - "description": "Users successfully added to team." - }, - "400": { - "description": "Invalid request (blank ID, wrong type, membership does not exist, user is already a member, user is not in the organization).", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } + "description": "Project exclusions successfully added to policy set." }, - "403": { - "description": "Forbidden. The organization is managed by HCP.", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -13541,16 +13153,40 @@ } } } - }, - "404": { - "description": "Team not found, or user unauthorized to perform action.", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } + } + } + }, + "delete": { + "operationId": "removePolicySetProjectExclusions", + "summary": "Remove Project Exclusions from a Policy Set", + "description": "Remove project exclusions from a policy set. project exclusions not currently in the set are ignored.", + "tags": [ + "policy-sets" + ], + "parameters": [ + { + "in": "path", + "name": "policy_set_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the policy set." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/projects-identifier-array-document" } } + } + }, + "responses": { + "204": { + "description": "Project exclusions successfully removed from policy set." }, "default": { "description": "Error details", @@ -13563,23 +13199,28 @@ } } } - }, - "delete": { - "operationId": "removeTeamMembersByOrgMembership", - "summary": "Remove Users from Team (by organization membership ID)", - "description": "Remove multiple users from a team using their organization membership IDs. This only removes users from this team; it does not delete the users from the organization.", + } + }, + "/policy-sets/{policy_set_id}/tag-selectors": { + "x-vis": [ + "public-beta" + ], + "post": { + "operationId": "addPolicySetTagSelectors", + "summary": "Add Tag Selectors to a Policy Set", + "description": "Add tag selectors to a policy set. Tag selectors define tag-based scoping rules for the policy set.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", "tags": [ - "teams" + "policy-sets" ], "parameters": [ { "in": "path", - "name": "team_id", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the team." + "description": "The ID of the policy set." } ], "requestBody": { @@ -13587,17 +13228,45 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/organization-memberships-identifier-array-document" + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tag-key": { + "type": "string", + "description": "The tag key to match." + }, + "tag-value": { + "type": "string", + "nullable": true, + "description": "The tag value to match." + }, + "is-exclude": { + "type": "boolean", + "description": "Whether this selector excludes matching workspaces." + } + }, + "required": [ + "tag-key", + "tag-value", + "is-exclude" + ] + } + } + } } } } }, "responses": { "204": { - "description": "Users successfully removed from team." + "description": "Tag selectors successfully added to policy set." }, - "400": { - "description": "Invalid request (blank ID, wrong type, membership does not exist, user is not a member).", + "404": { + "description": "Policy set not found or feature not enabled.", "content": { "application/vnd.api+json": { "schema": { @@ -13606,8 +13275,18 @@ } } }, - "403": { - "description": "Forbidden. The organization is managed by HCP, or attempting to remove the last active owner of the owners team.", + "422": { + "description": "Validation error, e.g. tag-based scoping conflicts with explicit associations.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -13615,9 +13294,71 @@ } } } + } + } + }, + "delete": { + "operationId": "removePolicySetTagSelectors", + "summary": "Remove Tag Selectors from a Policy Set", + "description": "Remove tag selectors from a policy set by their tag key and value.\n\nThis operation is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", + "tags": [ + "policy-sets" + ], + "parameters": [ + { + "in": "path", + "name": "policy_set_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the policy set." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tag-key": { + "type": "string", + "description": "The tag key to match." + }, + "tag-value": { + "type": "string", + "nullable": true, + "description": "The tag value to match." + }, + "is-exclude": { + "type": "boolean", + "description": "Whether this selector excludes matching workspaces." + } + }, + "required": [ + "tag-key", + "tag-value", + "is-exclude" + ] + } + } + } + } + } + } + }, + "responses": { + "204": { + "description": "Tag selectors successfully removed from policy set." }, "404": { - "description": "Team not found, or user unauthorized to perform action.", + "description": "Policy set not found or feature not enabled.", "content": { "application/vnd.api+json": { "schema": { @@ -13639,32 +13380,23 @@ } } }, - "/team-projects": { + "/policy-sets/{policy_set_id}/versions": { "get": { - "operationId": "listTeamProjects", - "summary": "List Team Access to a Project", - "description": "List all team access grants for a project.", + "operationId": "listPolicySetVersions", + "summary": "List Policy Set Versions", + "description": "List all versions of a policy set.", "tags": [ - "team-projects" + "policy-set-versions" ], "parameters": [ { - "in": "query", - "name": "filter[project][id]", + "in": "path", + "name": "policy_set_id", "schema": { "type": "string" }, "required": true, - "description": "The project ID to list team access for." - }, - { - "in": "query", - "name": "filter[team][id]", - "schema": { - "type": "string" - }, - "required": false, - "description": "Optionally filter by team ID." + "description": "The ID of the policy set." }, { "$ref": "#/components/parameters/page_number" @@ -13675,7 +13407,7 @@ ], "responses": { "200": { - "description": "List of team-project access grants", + "description": "List of policy set versions", "content": { "application/vnd.api+json": { "schema": { @@ -13684,7 +13416,7 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/team-projects" + "$ref": "#/components/schemas/policy-set-versions" } }, "meta": { @@ -13703,16 +13435,6 @@ } } }, - "404": { - "description": "Project not found or user unauthorized to perform action", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, "default": { "description": "Error details", "content": { @@ -13726,49 +13448,30 @@ } }, "post": { - "operationId": "addProjectTeamAccess", - "summary": "Add Team Access to a Project", - "description": "Add a team's access to a project.", + "operationId": "createPolicySetVersion", + "summary": "Create a Policy Set Version", + "description": "Create a new version for a policy set. The version will be in a pending state until policies are uploaded to it.", "tags": [ - "team-projects" + "policy-set-versions" ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/team-projects-envelope" - } - } + "parameters": [ + { + "in": "path", + "name": "policy_set_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the policy set." } - }, + ], "responses": { "201": { - "description": "Team access created", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/team-projects-envelope" - } - } - } - }, - "404": { - "description": "Project or team not found or user unauthorized to perform action", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "422": { - "description": "Malformed request body (missing attributes, wrong types, etc.)", + "description": "Policy set version created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/policy-set-versions-envelope" } } } @@ -13786,48 +13489,38 @@ } } }, - "/team-projects/{team_project_id}": { + "/policy-set-versions/{policy_set_version_id}": { "get": { - "operationId": "showProjectTeamAccess", - "summary": "Show a Team Access Relationship", - "description": "Get details about a team's access to a project.", + "operationId": "getPolicySetVersion", + "summary": "Get a Policy Set Version", + "description": "Get details about a specific policy set version.", "tags": [ - "team-projects" + "policy-set-versions" ], "parameters": [ { "in": "path", - "name": "team_project_id", + "name": "policy_set_version_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the team/project relationship." + "description": "The ID of the policy set version." } ], "responses": { "200": { - "description": "Team-project access details", + "description": "Policy set version details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/team-projects-envelope" + "$ref": "#/components/schemas/policy-set-versions-envelope" } } } }, - "404": { - "description": "Team access not found or user unauthorized to perform action", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "default": { - "description": "Error details", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -13837,48 +13530,40 @@ } } } - }, - "patch": { - "operationId": "updateProjectTeamAccess", - "summary": "Update Team Access to a Project", - "description": "Update a team's access level on a project.", + } + }, + "/policy-evaluations/{policy_evaluation_id}": { + "get": { + "operationId": "getPolicyEvaluation", + "summary": "Show a Policy Evaluation", + "description": "Get details about a specific policy evaluation.", "tags": [ - "team-projects" + "policy-evaluations" ], "parameters": [ { "in": "path", - "name": "team_project_id", + "name": "policy_evaluation_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the team/project relationship." + "description": "The ID of the policy evaluation to show." } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/team-projects-envelope" - } - } - } - }, "responses": { "200": { - "description": "Team access updated successfully", + "description": "Policy evaluation details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/team-projects-envelope" + "$ref": "#/components/schemas/policy-evaluations-envelope" } } } }, - "404": { - "description": "Team access not found or user unauthorized to perform action", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -13886,9 +13571,67 @@ } } } + } + } + } + }, + "/policy-evaluations/{policy_evaluation_id}/policy-set-outcomes": { + "get": { + "operationId": "listPolicySetOutcomes", + "summary": "List Policy Set Outcomes", + "description": "List the policy set outcomes associated with a policy evaluation.", + "tags": [ + "policy-evaluations" + ], + "parameters": [ + { + "in": "path", + "name": "policy_evaluation_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the policy evaluation to list outcomes for." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of policy set outcomes", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/policy-set-outcomes" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } }, - "422": { - "description": "Malformed request body (missing attributes, wrong types, etc.)", + "400": { + "description": "Invalid filter provided", "content": { "application/vnd.api+json": { "schema": { @@ -13908,35 +13651,34 @@ } } } - }, - "delete": { - "operationId": "removeProjectTeamAccess", - "summary": "Remove Team Access from a Project", - "description": "Remove a team's access from a project.", + } + }, + "/policy-set-outcomes/{policy_set_outcome_id}": { + "get": { + "operationId": "getPolicySetOutcome", + "summary": "Show a Policy Set Outcome", + "description": "Get details about a specific policy set outcome.", "tags": [ - "team-projects" + "policy-evaluations" ], "parameters": [ { "in": "path", - "name": "team_project_id", + "name": "policy_set_outcome_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the team/project relationship." + "description": "The ID of the policy set outcome to show." } ], "responses": { - "204": { - "description": "Team access removed successfully" - }, - "404": { - "description": "Team access not found or user unauthorized to perform action", + "200": { + "description": "Policy set outcome details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/policy-set-outcomes-envelope" } } } @@ -13954,32 +13696,23 @@ } } }, - "/team-workspaces": { + "/task-stages/{task_stage_id}/policy-evaluations": { "get": { - "operationId": "listTeamWorkspaces", - "summary": "List Team Access to a Workspace", - "description": "List all team access relationships. Optionally filter by workspace or team ID.", + "operationId": "listTaskStagePolicyEvaluations", + "summary": "List Policy Evaluations for a Task Stage", + "description": "List the policy evaluations associated with a task stage.", "tags": [ - "team-access" + "policy-evaluations" ], "parameters": [ { - "in": "query", - "name": "filter[workspace][id]", - "schema": { - "type": "string" - }, - "required": false, - "description": "The workspace ID to list team access for." - }, - { - "in": "query", - "name": "filter[team][id]", + "in": "path", + "name": "task_stage_id", "schema": { "type": "string" }, - "required": false, - "description": "The team ID to list workspace access for." + "required": true, + "description": "The ID of the task stage to list policy evaluations for." }, { "$ref": "#/components/parameters/page_number" @@ -13990,7 +13723,7 @@ ], "responses": { "200": { - "description": "List of team access relationships", + "description": "List of policy evaluations", "content": { "application/vnd.api+json": { "schema": { @@ -13999,7 +13732,7 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/team-workspaces" + "$ref": "#/components/schemas/policy-evaluations" } }, "meta": { @@ -14018,16 +13751,6 @@ } } }, - "404": { - "description": "Workspace not found or user unauthorized to perform action", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, "default": { "description": "Error details", "content": { @@ -14039,51 +13762,33 @@ } } } - }, + } + }, + "/plan-exports": { "post": { - "operationId": "addTeamAccess", - "summary": "Add Team Access to a Workspace", - "description": "Add a team's access to a workspace.", + "operationId": "createPlanExport", + "summary": "Create a Plan Export", + "description": "Export data from a plan in the specified format. The export process is asynchronous, and the resulting data becomes downloadable when its status is \"finished\".", "tags": [ - "team-access" + "plan-exports" ], "requestBody": { "required": true, "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/team-workspaces-envelope" + "$ref": "#/components/schemas/plan-exports-envelope" } } } }, "responses": { "201": { - "description": "Team access relationship created", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/team-workspaces-envelope" - } - } - } - }, - "404": { - "description": "Workspace or Team not found or user unauthorized to perform action", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "422": { - "description": "Malformed request body (missing attributes, wrong types, etc.)", + "description": "Plan export created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/plan-exports-envelope" } } } @@ -14101,42 +13806,32 @@ } } }, - "/team-workspaces/{team_workspace_id}": { + "/plan-exports/{id}": { "get": { - "operationId": "showTeamAccess", - "summary": "Show a Team Access Relationship", - "description": "Get details about a team's access to a workspace.", + "operationId": "showPlanExport", + "summary": "Show a Plan Export", + "description": "Get details about a specific plan export.", "tags": [ - "team-access" + "plan-exports" ], "parameters": [ { "in": "path", - "name": "team_workspace_id", + "name": "id", "schema": { "type": "string" }, "required": true, - "description": "The team/workspace relationship ID." + "description": "The ID of the plan export to show." } ], "responses": { "200": { - "description": "Team access relationship details", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/team-workspaces-envelope" - } - } - } - }, - "404": { - "description": "Team access not found or user unauthorized to perform action", + "description": "Plan export details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/plan-exports-envelope" } } } @@ -14153,47 +13848,30 @@ } } }, - "patch": { - "operationId": "updateTeamAccess", - "summary": "Update Team Access to a Workspace", - "description": "Update a team's access to a workspace.", + "delete": { + "operationId": "deletePlanExport", + "summary": "Delete a Plan Export", + "description": "Delete the exported plan data. Plan exports expire after one hour, but can be deleted manually.", "tags": [ - "team-access" + "plan-exports" ], "parameters": [ { "in": "path", - "name": "team_workspace_id", + "name": "id", "schema": { "type": "string" }, "required": true, - "description": "The team/workspace relationship ID." + "description": "The ID of the plan export to delete." } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/team-workspaces-envelope" - } - } - } - }, "responses": { - "200": { - "description": "Team access relationship updated", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/team-workspaces-envelope" - } - } - } + "204": { + "description": "Plan export deleted successfully" }, - "404": { - "description": "Team access not found or user unauthorized to perform action", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -14201,13 +13879,37 @@ } } } - }, - "422": { - "description": "Malformed request body (missing attributes, wrong types, etc.)", + } + } + } + }, + "/plan-exports/{id}/download": { + "get": { + "operationId": "downloadPlanExport", + "summary": "Download exported plan data", + "description": "Generate a temporary URL to the location of the exported plan data in a .tar.gz archive, then redirect to that link.", + "tags": [ + "plan-exports" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the plan export to download." + } + ], + "responses": { + "200": { + "description": ".tar.gz file containing the exported plan data.", "content": { - "application/vnd.api+json": { + "application/octet-stream": { "schema": { - "$ref": "#/components/schemas/errors" + "type": "string", + "format": "binary" } } } @@ -14223,41 +13925,39 @@ } } } - }, - "delete": { - "operationId": "removeTeamAccess", - "summary": "Remove Team Access to a Workspace", - "description": "Remove a team's access to a workspace.", + } + }, + "/assessment-results/{id}": { + "get": { + "summary": "Show an assessment result", + "operationId": "getAssessmentResult", "tags": [ - "team-access" + "assessment-results" ], "parameters": [ { + "name": "id", "in": "path", - "name": "team_workspace_id", + "required": true, + "description": "The external ID of the assessment result to show.", "schema": { "type": "string" - }, - "required": true, - "description": "The team/workspace relationship ID." + } } ], "responses": { - "204": { - "description": "Team access relationship deleted" - }, - "404": { - "description": "Team access not found or user unauthorized to perform action", + "200": { + "description": "The request was successful", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/assessment-results-envelope" } } } }, "default": { - "description": "Error details", + "description": "Assessment result not found, or user unauthorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -14269,88 +13969,40 @@ } } }, - "/tasks/integrations": { + "/assessment-results/{id}/json-output": { "get": { - "operationId": "listTaskIntegrations", - "tags": [ - "tasks" - ], - "summary": "List Integrations", - "description": "List all available integrations that can be used with tasks. \nBy default, only active integrations are returned.\n", + "operationId": "getAssessmentResultJSONOutput", + "summary": "Get the JSON assessment output", + "description": "This endpoint returns the JSON formatted assessment output.\nThis is only available when the assessment has succeeded and has JSON output data.\n", "parameters": [ { - "name": "search", - "in": "query", - "required": false, - "description": "Search integrations by name (case-insensitive, partial match).", - "schema": { - "type": "string", - "example": "cloud" - } - }, - { - "name": "category", - "in": "query", - "required": false, - "description": "Filter integrations by category.", - "schema": { - "type": "string", - "example": "cost-estimation" - } - }, - { - "name": "include_inactive", - "in": "query", - "required": false, - "description": "Include inactive integrations in the results.", + "name": "id", + "in": "path", + "description": "The external ID of the assessment result.", + "required": true, "schema": { - "type": "string", - "enum": [ - "true", - "false" - ], - "default": "false" + "type": "string" } - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" } ], + "tags": [ + "assessment-results" + ], "responses": { "200": { - "description": "OK", + "description": "Assessment result JSON output found and returned.", "content": { - "application/vnd.api+json": { + "application/json": { "schema": { "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/integrations" - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - } - } + "additionalProperties": true, + "description": "The JSON formatted assessment output with dynamic structure" } } } }, - "401": { - "description": "Unauthorized", + "404": { + "description": "Assessment result failed or JSON output is not available.", "content": { "application/vnd.api+json": { "schema": { @@ -14359,8 +14011,8 @@ } } }, - "422": { - "description": "Unprocessable Content", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -14372,60 +14024,43 @@ } } }, - "/workspaces/{workspace_id}/configuration-versions": { + "/assessment-results/{id}/json-schema": { "get": { - "operationId": "listConfigurationVersions", - "summary": "List Configuration Versions", - "description": "List configuration versions for a workspace.", - "tags": [ - "configuration-versions" - ], + "operationId": "getAssessmentResultJSONSchema", + "summary": "Get the JSON schema", + "description": "This endpoint returns the JSON schema for the assessment result.\nThis is only available when the assessment has succeeded and has provider schemas.\n", "parameters": [ { + "name": "id", "in": "path", - "name": "workspace_id", + "description": "The external ID of the assessment result.", + "required": true, "schema": { "type": "string" - }, - "required": true, - "description": "The ID of the workspace." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + } } ], + "tags": [ + "assessment-results" + ], "responses": { "200": { - "description": "List of configuration versions", + "description": "JSON schema found and returned.", "content": { - "application/vnd.api+json": { + "application/json": { "schema": { "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/configuration-versions" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } + "description": "The JSON schema of the assessment result" + } + } + } + }, + "404": { + "description": "Assessment result failed or JSON schema is not available.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -14441,42 +14076,45 @@ } } } - }, - "post": { - "operationId": "createConfigurationVersion", - "summary": "Create Configuration Version", - "description": "Create a new configuration version in a workspace.", - "tags": [ - "configuration-versions" - ], + } + }, + "/assessment-results/{id}/sanitized-plan": { + "get": { + "operationId": "getAssessmentResultSanitizedPlan", + "summary": "Get the sanitized plan", + "description": "This endpoint returns the sanitized plan for the assessment result.\nThis is only available when HYOK is enabled for the organization,\nthe assessment has succeeded, and a sanitized plan is available.\n", "parameters": [ { + "name": "id", "in": "path", - "name": "workspace_id", + "description": "The external ID of the assessment result.", + "required": true, "schema": { "type": "string" - }, - "required": true, - "description": "The ID of the workspace." + } } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/configuration-versions-envelope" + "tags": [ + "assessment-results" + ], + "responses": { + "200": { + "description": "Sanitized plan found and returned.", + "content": { + "application/json": { + "schema": { + "type": "object", + "description": "The sanitized plan output" + } } } - } - }, - "responses": { - "201": { - "description": "Configuration version created", + }, + "404": { + "description": "HYOK not available, assessment result failed, or sanitized plan is not available.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/configuration-versions-envelope" + "$ref": "#/components/schemas/errors" } } } @@ -14494,32 +14132,60 @@ } } }, - "/configuration-versions/{configuration_version_id}": { + "/assessment-results/{id}/log-output": { "get": { - "operationId": "getConfigurationVersion", - "summary": "Get Configuration Version", - "description": "Get details of a specific configuration version.", - "tags": [ - "configuration-versions" - ], + "operationId": "getAssessmentResultLogOutput", + "summary": "Get the log output", + "description": "This endpoint returns the log output for the assessment result.\nSupports both JSON and plain text formats based on the Accept header.\nQuery parameters allow for pagination of log output.\n", "parameters": [ { + "name": "id", "in": "path", - "name": "configuration_version_id", + "description": "The external ID of the assessment result.", + "required": true, "schema": { "type": "string" - }, - "required": true, - "description": "The ID of the configuration version." + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of bytes to return", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "offset", + "in": "query", + "description": "Byte offset to start reading from", + "required": false, + "schema": { + "type": "integer" + } + }, + { + "name": "tail", + "in": "query", + "description": "If true, return the last N bytes instead of the first N bytes", + "required": false, + "schema": { + "type": "boolean" + } } ], + "tags": [ + "assessment-results" + ], "responses": { "200": { - "description": "Configuration version details", + "description": "Log output returned successfully.", "content": { - "application/vnd.api+json": { + "text/plain": { "schema": { - "$ref": "#/components/schemas/configuration-versions-envelope" + "type": "string", + "description": "The log output in plain text format" } } } @@ -14537,38 +14203,37 @@ } } }, - "/configuration-versions/{configuration_version_id}/ingress-attributes": { + "/applies/{id}": { "get": { - "operationId": "getIngressAttributes", - "summary": "Get Ingress Attributes", - "description": "Get commit information for a configuration version.", + "summary": "Show an apply", + "operationId": "getApply", "tags": [ - "configuration-versions" + "applies" ], "parameters": [ { + "name": "id", "in": "path", - "name": "configuration_version_id", + "required": true, + "description": "The ID of the apply to show.", "schema": { "type": "string" - }, - "required": true, - "description": "The ID of the configuration version." + } } ], "responses": { "200": { - "description": "Ingress attributes details", + "description": "The request was successful", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/ingress-attributes" + "$ref": "#/components/schemas/applies-envelope" } } } }, "default": { - "description": "Error details", + "description": "Apply not found, or user unauthorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -14580,31 +14245,38 @@ } } }, - "/configuration-versions/{configuration_version_id}/actions/archive": { - "post": { - "operationId": "archiveConfigurationVersion", - "summary": "Archive Configuration Version", - "description": "Archive the uploaded files for a configuration version.", + "/applies/{id}/errored-state": { + "get": { + "summary": "Recover a failed state upload after applying", + "operationId": "getApplyErroredState", "tags": [ - "configuration-versions" + "applies" ], "parameters": [ { + "name": "id", "in": "path", - "name": "configuration_version_id", + "required": true, + "description": "The ID of the apply to recover state for.", "schema": { "type": "string" - }, - "required": true, - "description": "The ID of the configuration version." + } } ], "responses": { - "202": { - "description": "Archive process initiated" + "307": { + "description": "Errored state available and user is authorized to read it", + "headers": { + "Location": { + "description": "Storage URL to raw state file", + "schema": { + "type": "string" + } + } + } }, - "409": { - "description": "Configuration version was in a non-archivable state or the configuration version was created with VCS and cannot be archived through the API.", + "default": { + "description": "Apply not found, errored state not uploaded, or user unauthorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -14612,6 +14284,35 @@ } } } + } + } + } + }, + "/applies/{id}/actions/soft-delete-backing-data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "softDeleteApplyBackingData", + "summary": "Soft Delete Apply Backing Data", + "description": "Mark the backing files associated with this apply for garbage collection. Terraform permanently deletes backing files after a set number of days unless the apply is restored.\n\nThis operation is only available in Terraform Enterprise.", + "tags": [ + "applies" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the apply to mark for garbage collection." + } + ], + "responses": { + "204": { + "description": "Apply backing data marked for garbage collection" }, "default": { "description": "Error details", @@ -14626,36 +14327,70 @@ } } }, - "/configuration-versions/{configuration_version_id}/download": { - "get": { - "operationId": "downloadConfigurationVersion", - "summary": "Download Configuration Version", - "description": "Generate a temporary URL to download the configuration version files.", + "/applies/{id}/actions/restore-backing-data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "restoreApplyBackingData", + "summary": "Restore Apply Backing Data", + "description": "Restore backing files associated with an apply that was previously marked for garbage collection. This restores the apply back to its finalized state.\n\nThis operation is only available in Terraform Enterprise.", "tags": [ - "configuration-versions" + "applies" ], "parameters": [ { "in": "path", - "name": "configuration_version_id", + "name": "id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the configuration version." + "description": "The ID of the apply to restore." } ], "responses": { - "302": { - "description": "Temporary download URL generated", - "headers": { - "Location": { - "description": "Storage URL to .tar.gz file containing the configuration version", + "204": { + "description": "Apply backing data restore initiated" + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { "schema": { - "type": "string" + "$ref": "#/components/schemas/errors" } } } + } + } + } + }, + "/applies/{id}/actions/permanently-delete-backing-data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "permanentlyDeleteApplyBackingData", + "summary": "Permanently Delete Apply Backing Data", + "description": "Permanently delete the backing files associated with an apply that has been soft deleted. This action cannot be undone.\n\nThis operation is only available in Terraform Enterprise.", + "tags": [ + "applies" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the apply to permanently delete backing data for." + } + ], + "responses": { + "204": { + "description": "Apply backing data permanently deleted" }, "default": { "description": "Error details", @@ -14670,70 +14405,200 @@ } } }, - "/organizations/{organization_name}/vcs-events": { - "get": { - "operationId": "listOrganizationVcsEvents", - "summary": "List VCS Events", - "description": "List VCS events for an organization.", + "/assessments/{id}/actions/soft-delete-backing-data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "softDeleteAssessmentBackingData", + "summary": "Soft Delete Assessment Backing Data", + "description": "Mark the backing files associated with this assessment for garbage collection. Terraform permanently deletes backing files after a set number of days unless the assessment is restored.\n\nThis operation is only available in Terraform Enterprise.", "tags": [ - "vcs-events" + "assessments" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "id", "schema": { "type": "string" }, "required": true, - "description": "The name of the organization to list VCS events from." + "description": "The ID of the assessment to mark for garbage collection." + } + ], + "responses": { + "204": { + "description": "Assessment backing data marked for garbage collection" }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/assessments/{id}/actions/restore-backing-data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "restoreAssessmentBackingData", + "summary": "Restore Assessment Backing Data", + "description": "Restore backing files associated with an assessment that was previously marked for garbage collection. This restores the assessment back to its finalized state.\n\nThis operation is only available in Terraform Enterprise.", + "tags": [ + "assessments" + ], + "parameters": [ { - "in": "query", - "name": "filter[from]", + "in": "path", + "name": "id", "schema": { - "type": "string", - "format": "date-time" + "type": "string" }, - "required": false, - "description": "RFC3339 formatted UTC timestamp. If omitted, defaults to 10 days ago." + "required": true, + "description": "The ID of the assessment to restore." + } + ], + "responses": { + "204": { + "description": "Assessment backing data restore initiated" }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/assessments/{id}/actions/permanently-delete-backing-data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "permanentlyDeleteAssessmentBackingData", + "summary": "Permanently Delete Assessment Backing Data", + "description": "Permanently delete the backing files associated with an assessment that has been soft deleted. This action cannot be undone.\n\nThis operation is only available in Terraform Enterprise.", + "tags": [ + "assessments" + ], + "parameters": [ { - "in": "query", - "name": "filter[to]", + "in": "path", + "name": "id", "schema": { - "type": "string", - "format": "date-time" + "type": "string" }, - "required": false, - "description": "RFC3339 formatted UTC timestamp. If omitted, defaults to now." + "required": true, + "description": "The ID of the assessment to permanently delete backing data for." + } + ], + "responses": { + "204": { + "description": "Assessment backing data permanently deleted" + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/cost-estimates/{id}": { + "get": { + "summary": "Show a cost estimate", + "operationId": "showCostEstimate", + "tags": [ + "cost-estimates" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the cost estimate to show.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The request was successful", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/cost-estimates-envelope" + } + } + } }, + "default": { + "description": "Cost estimate not found, or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/state-versions": { + "get": { + "operationId": "listStateVersions", + "summary": "List State Versions for a Workspace", + "description": "List state versions for a workspace, filtered by organization and workspace name.", + "tags": [ + "state-versions" + ], + "parameters": [ { "in": "query", - "name": "filter[oauth_client_external_ids]", + "name": "filter[workspace][name]", "schema": { "type": "string" }, - "required": false, - "description": "Comma-separated list of OAuth client external IDs to filter by." + "required": true, + "description": "The name of the workspace to list state versions for." }, { "in": "query", - "name": "filter[levels]", + "name": "filter[organization][name]", "schema": { "type": "string" }, - "required": false, - "description": "Comma-separated list of event levels to filter by. Accepted values are \"info\" and \"error\"." + "required": true, + "description": "The name of the organization that owns the workspace." }, { "in": "query", - "name": "include", + "name": "filter[status]", "schema": { "type": "string" }, "required": false, - "description": "Allows including related resource data. Only \"oauth_client\" is supported." + "description": "Filter state versions by status. One or more comma-separated values from pending, finalized, or discarded." }, { "$ref": "#/components/parameters/page_number" @@ -14744,7 +14609,7 @@ ], "responses": { "200": { - "description": "List of VCS events", + "description": "List of state versions", "content": { "application/vnd.api+json": { "schema": { @@ -14753,7 +14618,7 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/vcs-events" + "$ref": "#/components/schemas/state-versions" } }, "meta": { @@ -14785,280 +14650,223 @@ } } }, - "/organizations/{organization_name}/vcs/tree": { + "/state-versions/{state_version_id}": { "get": { - "operationId": "getVcsTree", - "summary": "List directories in a repository", - "description": "This endpoint returns a list of directories in a repository \nat the root or at a specific reference (branch, tag, or commit SHA).\nNote: This endpoint only returns directories, not files.\n", + "operationId": "getStateVersion", + "summary": "Show a State Version", + "description": "Show details for a specific state version.", "tags": [ - "vcs" + "state-versions" ], "parameters": [ { - "name": "organization_name", "in": "path", - "required": true, - "schema": { - "type": "string" - }, - "description": "The name of the organization" - }, - { - "name": "oauth_token_id", - "in": "query", - "required": true, + "name": "state_version_id", "schema": { "type": "string" }, - "description": "The OAuth token ID to authenticate with the VCS provider" - }, - { - "name": "identifier", - "in": "query", "required": true, - "schema": { - "type": "string" - }, - "description": "The repository identifier (e.g., \"owner/repo\")" - }, - { - "name": "branch", - "in": "query", - "required": false, - "schema": { - "type": "string" - }, - "description": "The branch, tag, or commit SHA to list directories for. \nIf not provided, the default branch will be used.\n" - }, - { - "name": "githubAppInstallationId", - "in": "query", - "required": false, - "schema": { - "type": "string" - }, - "description": "The GitHub App installation ID (only needed when using GitHub App authentication)" + "description": "The ID of the state version to show." } ], "responses": { "200": { - "description": "Successfully retrieved repository directories", + "description": "State version details", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Unique identifier for the directory" - }, - "type": { - "type": "string", - "enum": [ - "vcs-tree" - ] - } - } - } - } - } + "$ref": "#/components/schemas/state-versions-envelope" } } } }, - "404": { - "description": "Repository not found or user doesn't have access" - } - }, - "security": [ - { - "bearerAuth": [] + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } } - ] + } } }, - "/organizations/{organization_name}/vcs/repo": { + "/state-versions/{state_version_id}/outputs": { "get": { - "operationId": "checkVcsRepository", - "summary": "Check if a repository exists", - "description": "This endpoint checks if a repository exists and is accessible to the user.\n", + "operationId": "listStateVersionOutputs", + "summary": "List State Version Outputs", + "description": "List the output values associated with a specific state version.", "tags": [ - "vcs" + "state-versions" ], "parameters": [ { - "name": "organization_name", "in": "path", - "required": true, + "name": "state_version_id", "schema": { "type": "string" }, - "description": "The name of the organization" + "required": true, + "description": "The ID of the state version whose outputs to list." }, { - "name": "oauth_token_id", - "in": "query", - "required": true, - "schema": { - "type": "string" - }, - "description": "The OAuth token ID to authenticate with the VCS provider" + "$ref": "#/components/parameters/page_number" }, { - "name": "identifier", - "in": "query", - "required": true, - "schema": { - "type": "string" - }, - "description": "The repository identifier (e.g., \"owner/repo\")" + "$ref": "#/components/parameters/page_size" } ], "responses": { "200": { - "description": "Successfully checked repository existence", + "description": "List of state version outputs", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/vcs-repo-check-envelope" - } - } - } - }, - "404": { - "description": "OAuth token not found or user doesn't have access" - } - }, - "security": [ - { - "bearerAuth": [] + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/state-version-outputs" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } } - ] + } } }, - "/organizations/{organization_name}/registry-modules/validation": { - "get": { - "operationId": "validateRegistryModuleNames", - "summary": "Check if a module name and provider combination is available", - "description": "This endpoint checks if a module name and provider combination is available for use within an organization.\nIt returns a validation result indicating whether the name is already in use.\n", + "/state-versions/{state_version_id}/actions/soft_delete_backing_data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "softDeleteStateVersionBackingData", + "summary": "Soft Delete State Version Backing Data", + "description": "Mark the backing files associated with this state version for garbage collection. Terraform permanently deletes backing files after a set number of days unless the state version is restored.\n\nThis operation is only available in Terraform Enterprise.", "tags": [ - "registry" + "state-versions" ], "parameters": [ { - "name": "organization_name", "in": "path", - "required": true, - "schema": { - "type": "string" - }, - "description": "The name of the organization" - }, - { - "name": "name", - "in": "query", - "required": true, + "name": "state_version_id", "schema": { "type": "string" }, - "description": "The name of the module to validate" - }, - { - "name": "provider", - "in": "query", "required": true, - "schema": { - "type": "string" - }, - "description": "The provider of the module to validate" + "description": "The ID of the state version to mark for garbage collection." } ], "responses": { - "200": { - "description": "Successfully validated the module name and provider", + "204": { + "description": "State version backing data marked for garbage collection" + }, + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/registry-module-address-validations-envelope" + "$ref": "#/components/schemas/errors" } } } - }, - "400": { - "description": "Bad request" - }, - "401": { - "description": "Unauthorized" - }, - "404": { - "description": "Organization not found" } } } }, - "/organizations/{organization_name}/ssh-keys": { - "get": { - "operationId": "listSshKeys", + "/state-versions/{state_version_id}/actions/restore_backing_data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "restoreStateVersionBackingData", + "summary": "Restore State Version Backing Data", + "description": "Restore backing files associated with a state version that was previously marked for garbage collection. This restores the state version back to its finalized state.\n\nThis operation is only available in Terraform Enterprise.", "tags": [ - "ssh-keys" + "state-versions" ], - "summary": "List SSH Keys", - "description": "List all SSH keys for an organization.", "parameters": [ { - "name": "organization_name", "in": "path", - "required": true, - "description": "The name of the organization.", + "name": "state_version_id", "schema": { - "type": "string", - "example": "my-organization" - } - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "type": "string" + }, + "required": true, + "description": "The ID of the state version to restore." } ], "responses": { - "200": { - "description": "OK", + "204": { + "description": "State version backing data restore initiated" + }, + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ssh-keys" - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - } - } + "$ref": "#/components/schemas/errors" } } } + } + } + } + }, + "/state-versions/{state_version_id}/actions/permanently_delete_backing_data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "permanentlyDeleteStateVersionBackingData", + "summary": "Permanently Delete State Version Backing Data", + "description": "Permanently delete the backing files associated with a state version that has been soft deleted. This action cannot be undone.\n\nThis operation is only available in Terraform Enterprise.", + "tags": [ + "state-versions" + ], + "parameters": [ + { + "in": "path", + "name": "state_version_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the state version to permanently delete backing data for." + } + ], + "responses": { + "204": { + "description": "State version backing data permanently deleted" }, - "404": { - "description": "Not Found", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -15068,24 +14876,25 @@ } } } - }, + } + }, + "/workspaces/{workspace_id}/state-versions": { "post": { - "operationId": "createSshKey", + "operationId": "createStateVersion", + "summary": "Create a State Version", + "description": "Create a state version and set it as the current state version for the given workspace. The workspace must be locked by the user creating the state version.", "tags": [ - "ssh-keys" + "state-versions" ], - "summary": "Create an SSH Key", - "description": "Create a new SSH key for an organization.", "parameters": [ { - "name": "organization_name", "in": "path", - "required": true, - "description": "The name of the organization.", + "name": "workspace_id", "schema": { - "type": "string", - "example": "my-organization" - } + "type": "string" + }, + "required": true, + "description": "The ID of the workspace to create the state version in." } ], "requestBody": { @@ -15093,34 +14902,24 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/ssh-keys-envelope" + "$ref": "#/components/schemas/state-versions-envelope" } } } }, "responses": { "201": { - "description": "Created", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/ssh-keys-envelope" - } - } - } - }, - "404": { - "description": "Not Found", + "description": "State version created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/state-versions-envelope" } } } }, - "422": { - "description": "Unprocessable Content", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -15130,41 +14929,48 @@ } } } - } - }, - "/ssh-keys/{ssh_key_id}": { - "get": { - "operationId": "getSshKey", + }, + "patch": { + "operationId": "rollbackStateVersion", + "summary": "Rollback to a Previous State Version", + "description": "Create a state version by duplicating the specified state version and set it as the current state version for the given workspace. The workspace must be locked by the user performing the rollback.", "tags": [ - "ssh-keys" + "state-versions" ], - "summary": "Get an SSH Key", - "description": "Retrieve the details of a single SSH key.", "parameters": [ { - "name": "ssh_key_id", "in": "path", - "required": true, - "description": "The ID of the SSH key.", + "name": "workspace_id", "schema": { - "type": "string", - "example": "sshkey-xxxxxxxxxxxxxxxx" - } + "type": "string" + }, + "required": true, + "description": "The ID of the workspace to rollback the state version in." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/state-versions-envelope" + } + } + } + }, "responses": { - "200": { - "description": "OK", + "201": { + "description": "State version rollback created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/ssh-keys-envelope" + "$ref": "#/components/schemas/state-versions-envelope" } } } }, - "404": { - "description": "Not Found", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -15174,59 +14980,40 @@ } } } - }, - "patch": { - "operationId": "updateSshKey", + } + }, + "/state-version-outputs/{state_version_output_id}": { + "get": { + "operationId": "getStateVersionOutput", + "summary": "Show a State Version Output", + "description": "Show details for a specific state version output.", "tags": [ - "ssh-keys" + "state-version-outputs" ], - "summary": "Update an SSH Key", - "description": "Update the name of an SSH key.", "parameters": [ { - "name": "ssh_key_id", + "name": "state_version_output_id", "in": "path", "required": true, - "description": "The ID of the SSH key.", + "description": "The ID of the state version output to show.", "schema": { - "type": "string", - "example": "sshkey-xxxxxxxxxxxxxxxx" + "type": "string" } } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/ssh-keys-envelope" - } - } - } - }, "responses": { "200": { - "description": "OK", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/ssh-keys-envelope" - } - } - } - }, - "404": { - "description": "Not Found", + "description": "The request was successful", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/state-version-outputs-envelope" } } } }, - "422": { - "description": "Unprocessable Content", + "default": { + "description": "State version output not found or user not authorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -15236,32 +15023,58 @@ } } } - }, - "delete": { - "operationId": "deleteSshKey", + } + }, + "/workspaces/{workspace_id}/current-state-version-outputs": { + "get": { + "operationId": "getCurrentStateVersionOutputs", + "summary": "Show Current State Version Outputs for a Workspace", + "description": "List the current state version outputs for a workspace. Sensitive output values are not revealed and will be returned as null. Organization users who do not have permission to read state versions may use this endpoint to fetch the latest output values for a workspace.", "tags": [ - "ssh-keys" + "state-version-outputs" ], - "summary": "Delete an SSH Key", - "description": "Delete an SSH key.", "parameters": [ { - "name": "ssh_key_id", + "name": "workspace_id", "in": "path", "required": true, - "description": "The ID of the SSH key.", + "description": "The ID of the workspace to read outputs from.", "schema": { - "type": "string", - "example": "sshkey-xxxxxxxxxxxxxxxx" + "type": "string" } } ], "responses": { - "204": { - "description": "No Content" + "200": { + "description": "The request was successful", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/state-version-outputs" + } + } + } + } + } + } }, - "404": { - "description": "Not Found", + "503": { + "description": "State version outputs are being processed and are not yet ready. Retry the request.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "State version outputs not found or user not authorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -15273,32 +15086,26 @@ } } }, - "/workspaces/{workspace_id}/change-requests": { + "/organizations/{organization_name}/hyok-configurations": { + "x-vis": [ + "hcpt" + ], "get": { - "operationId": "listWorkspaceChangeRequests", - "summary": "List Change Requests in a Workspace", - "description": "List all change requests for a workspace.", + "operationId": "listHyokConfigurations", + "summary": "List HYOK Configurations", + "description": "List all HYOK configurations in an organization\n\nThis operation is only available in HCP Terraform.", "tags": [ - "change-requests" + "hyok" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The workspace ID." - }, - { - "in": "query", - "name": "archive", - "schema": { - "type": "boolean" - }, - "required": false, - "description": "When true, returns only archived change requests. When false, returns only unarchived change requests. When omitted, returns all change requests ordered by creation date." + "description": "The name of the organization" }, { "$ref": "#/components/parameters/page_number" @@ -15309,7 +15116,7 @@ ], "responses": { "200": { - "description": "List of change requests", + "description": "Success", "content": { "application/vnd.api+json": { "schema": { @@ -15318,9 +15125,12 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/workspace-change-requests" + "$ref": "#/components/schemas/hyok-configurations" } }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, "meta": { "type": "object", "properties": { @@ -15328,9 +15138,6 @@ "$ref": "#/components/schemas/pagination" } } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" } } } @@ -15338,7 +15145,7 @@ } }, "default": { - "description": "Error details", + "description": "Organization not found, or user unauthorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -15348,34 +15155,42 @@ } } } - } - }, - "/change-requests/{change_request_id}": { - "get": { - "operationId": "showChangeRequest", - "summary": "Show a Change Request", - "description": "Get details about a specific change request.", + }, + "post": { + "operationId": "createHyokConfiguration", + "summary": "Create HYOK Configuration", + "description": "Create a new HYOK configuration\n\nThis operation is only available in HCP Terraform.", "tags": [ - "change-requests" + "hyok" ], "parameters": [ { "in": "path", - "name": "change_request_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The change request ID." + "description": "Name of the organization" } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/hyok-configurations-envelope" + } + } + } + }, "responses": { - "200": { - "description": "Change request details", + "201": { + "description": "HYOK Configuration created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspace-change-requests-envelope" + "$ref": "#/components/schemas/hyok-configurations-envelope" } } } @@ -15393,35 +15208,76 @@ } } }, - "/change-requests/{change_request_id}/actions/archive": { - "get": { - "operationId": "getChangeRequestArchive", - "summary": "Get Change Request Archive Status", - "description": "Get the current state of a change request, including its archive status.", + "/organizations/{organization_name}/hyok-configurations/test": { + "x-vis": [ + "hcpt" + ], + "post": { + "operationId": "testUnpersistedHyokConfiguration", + "summary": "Test new HYOK configuration", + "description": "Test an HYOK configuration that has yet to be saved on HCP Terraform. The test ensures that the configuration is set up correctly to connect to the specified KMS.\n\nThis operation is only available in HCP Terraform.", "tags": [ - "change-requests" + "hyok" ], "parameters": [ { "in": "path", - "name": "change_request_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The change request ID." + "description": "Name of the organization" } ], - "responses": { - "200": { - "description": "Change request details", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspace-change-requests-envelope" + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": [ + "hyok-configuration", + "oidc-configuration" + ], + "properties": { + "hyok-configuration": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/hyok-configurations" + } + } + }, + "oidc-configuration": { + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/aws-oidc-configurations" + }, + { + "$ref": "#/components/schemas/gcp-oidc-configurations" + }, + { + "$ref": "#/components/schemas/azure-oidc-configurations" + }, + { + "$ref": "#/components/schemas/vault-oidc-configurations" + } + ] + } + } + } } } } + } + }, + "responses": { + "204": { + "description": "HYOK Configuration successfully tested and verified" }, "default": { "description": "Error details", @@ -15434,42 +15290,47 @@ } } } - }, + } + }, + "/organizations/{organization_name}/oidc-configurations": { + "x-vis": [ + "hcpt" + ], "post": { - "operationId": "archiveChangeRequest", - "summary": "Archive a Change Request", - "description": "Archive a change request to mark it as completed.", + "operationId": "createOidcConfiguration", + "summary": "Create OIDC Configuration", + "description": "Create a new OIDC configuration\n\nThis operation is only available in HCP Terraform.", "tags": [ - "change-requests" + "hyok" ], "parameters": [ { "in": "path", - "name": "change_request_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The change request ID." + "description": "Name of the organization" } ], - "responses": { - "200": { - "description": "Change request successfully archived", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspace-change-requests-envelope" - } + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/oidc-configuration-envelope" } } - }, - "400": { - "description": "The change request is already archived.", + } + }, + "responses": { + "201": { + "description": "OIDC Configuration created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/errors" + "$ref": "#/components/schemas/oidc-configuration-envelope" } } } @@ -15487,41 +15348,35 @@ } } }, - "/oauth-clients/{oauth_client_id}": { + "/hyok-configurations/{hyok_configuration_id}": { + "x-vis": [ + "hcpt" + ], "get": { - "operationId": "getOAuthClient", - "summary": "Get an OAuth Client", - "description": "Show details of an existing OAuth client.", + "operationId": "getHyokConfiguration", + "summary": "Get HYOK configuration details", + "description": "Get details about an HYOK configuration\n\nThis operation is only available in HCP Terraform.", "tags": [ - "oauth-clients" + "hyok" ], "parameters": [ { "in": "path", - "name": "oauth_client_id", + "name": "hyok_configuration_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the OAuth Client." - }, - { - "in": "query", - "name": "show_affected_workspaces", - "schema": { - "type": "boolean" - }, - "required": false, - "description": "If true, includes names of up to 25 affected workspaces and the total count." + "description": "HYOK Configuration ID" } ], "responses": { "200": { - "description": "OAuth Client details", + "description": "HYOK Configuration details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/oauth-clients-envelope" + "$ref": "#/components/schemas/hyok-configurations-envelope" } } } @@ -15539,21 +15394,21 @@ } }, "patch": { - "operationId": "updateOAuthClient", - "summary": "Update an OAuth Client", - "description": "Update settings of an existing OAuth client.", + "operationId": "updateHyokConfiguration", + "summary": "Update HYOK Configuration", + "description": "Update an HYOK configuration\n\nThis operation is only available in HCP Terraform.", "tags": [ - "oauth-clients" + "hyok" ], "parameters": [ { "in": "path", - "name": "oauth_client_id", + "name": "hyok_configuration_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the OAuth Client to update." + "description": "HYOK configuration ID" } ], "requestBody": { @@ -15561,18 +15416,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/oauth-clients-envelope" + "$ref": "#/components/schemas/hyok-configurations-envelope" } } } }, "responses": { "200": { - "description": "OAuth Client updated", + "description": "HYOK configuration updated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/oauth-clients-envelope" + "$ref": "#/components/schemas/hyok-configurations-envelope" } } } @@ -15590,68 +15445,26 @@ } }, "delete": { - "operationId": "destroyOAuthClient", - "summary": "Destroy an OAuth Client", - "description": "Remove an existing OAuth client and unlink any associated workspaces.", + "operationId": "deleteHyokConfiguration", + "summary": "Delete HYOK Configuration", + "description": "Delete an HYOK configuration. Can only be performed on unused configurations.\n\nThis operation is only available in HCP Terraform.", "tags": [ - "oauth-clients" + "hyok" ], "parameters": [ { "in": "path", - "name": "oauth_client_id", + "name": "hyok_configuration_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the OAuth Client to destroy." + "description": "HYOK Configuration ID" } ], "responses": { "204": { - "description": "OAuth Client successfully destroyed." - }, - "default": { - "description": "Error details", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - } - } - } - }, - "/oauth-clients": { - "post": { - "operationId": "createOAuthClient", - "summary": "Create an OAuth Client", - "description": "Create a VCS connection between an organization and a VCS provider. The organization is specified via the `organization-id` attribute. This endpoint allows you to provide a pre-generated OAuth token string instead of going through the OAuth Application flow.\n", - "tags": [ - "oauth-clients" - ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/oauth-clients-envelope" - } - } - } - }, - "responses": { - "201": { - "description": "OAuth Client created", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/oauth-clients-envelope" - } - } - } + "description": "HYOK configuration deleted" }, "default": { "description": "Error details", @@ -15666,32 +15479,26 @@ } } }, - "/organizations/{organization_name}/oauth-clients": { + "/hyok-configurations/{hyok_configuration_id}/hyok-customer-key-versions": { + "x-vis": [ + "hcpt" + ], "get": { - "operationId": "listOAuthClients", - "summary": "List OAuth Clients", - "description": "List all VCS connections between an organization and its VCS providers.", + "operationId": "listHyokCustomerKeyVersions", + "summary": "List HYOK Customer Key Versions", + "description": "List all HYOK Customer Key Versions for an HYOK Configuration\n\nThis operation is only available in HCP Terraform.", "tags": [ - "oauth-clients" + "hyok" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "hyok_configuration_id", "schema": { "type": "string" }, "required": true, - "description": "The name of the organization." - }, - { - "in": "query", - "name": "show_affected_workspaces", - "schema": { - "type": "boolean" - }, - "required": false, - "description": "If true, includes names of up to 25 affected workspaces and total count per client." + "description": "HYOK Configuration ID" }, { "$ref": "#/components/parameters/page_number" @@ -15702,7 +15509,7 @@ ], "responses": { "200": { - "description": "List of OAuth Clients", + "description": "Success", "content": { "application/vnd.api+json": { "schema": { @@ -15711,9 +15518,12 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/oauth-clients" + "$ref": "#/components/schemas/hyok-customer-key-versions" } }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, "meta": { "type": "object", "properties": { @@ -15721,9 +15531,6 @@ "$ref": "#/components/schemas/pagination" } } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" } } } @@ -15741,42 +15548,40 @@ } } } - }, + } + }, + "/hyok-configurations/{hyok_configuration_id}/actions/revoke": { + "x-vis": [ + "hcpt" + ], "post": { - "operationId": "createOAuthClientForOrganization", - "summary": "Create an OAuth Client for an Organization", - "description": "Create a VCS connection between an organization and a VCS provider. This endpoint allows you to provide a pre-generated OAuth token string instead of going through the OAuth Application flow.\n", + "operationId": "revokeHyokConfiguration", + "summary": "Revoke HYOK configuration", + "description": "Revoke an HYOK configuration, instructing HCP Terraform to migrate off of the described key.\n\nThis operation is only available in HCP Terraform.", "tags": [ - "oauth-clients" + "hyok" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "hyok_configuration_id", "schema": { "type": "string" }, "required": true, - "description": "The name of the organization." + "description": "HYOK Configuration ID" } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/oauth-clients-envelope" - } - } - } - }, "responses": { - "201": { - "description": "OAuth Client created", + "202": { + "description": "HYOK Configuration revocation initiated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/oauth-clients-envelope" + "type": "string", + "enum": [ + "null" + ] } } } @@ -15794,38 +15599,31 @@ } } }, - "/oauth-clients/{oauth_client_id}/relationships/projects": { + "/hyok-configurations/{hyok_configuration_id}/actions/test": { + "x-vis": [ + "hcpt" + ], "post": { - "operationId": "attachOAuthClientToProjects", - "summary": "Attach an OAuth Client to Projects", - "description": "Attach an OAuth client to one or more projects.", + "operationId": "testHyokConfiguration", + "summary": "Test HYOK configuration", + "description": "Test an HYOK configuration to ensure that it is set up correctly to connect to the specified KMS.\n\nThis operation is only available in HCP Terraform.", "tags": [ - "oauth-clients" + "hyok" ], "parameters": [ { "in": "path", - "name": "oauth_client_id", + "name": "hyok_configuration_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the OAuth Client to attach to projects." + "description": "HYOK Configuration ID" } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/projects-identifier-array-document" - } - } - } - }, "responses": { "204": { - "description": "OAuth Client successfully attached to projects." + "description": "HYOK Configuration successfully tested and verified" }, "default": { "description": "Error details", @@ -15838,38 +15636,40 @@ } } } - }, - "delete": { - "operationId": "detachOAuthClientFromProjects", - "summary": "Detach an OAuth Client from Projects", - "description": "Detach an OAuth client from one or more projects.", + } + }, + "/hyok-customer-key-versions/{hyok_customer_key_version_id}": { + "x-vis": [ + "hcpt" + ], + "get": { + "operationId": "getHyokCustomerKeyVersion", + "summary": "Get HYOK Customer Key Version details", + "description": "Get details about a HYOK Customer Key Version\n\nThis operation is only available in HCP Terraform.", "tags": [ - "oauth-clients" + "hyok" ], "parameters": [ { "in": "path", - "name": "oauth_client_id", + "name": "hyok_customer_key_version_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the OAuth Client to detach from projects." + "description": "HYOK Customer Key Version ID" } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/projects-identifier-array-document" + "responses": { + "200": { + "description": "HYOK Customer Key Version details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/hyok-customer-key-versions-envelope" + } } } - } - }, - "responses": { - "204": { - "description": "OAuth Client successfully detached from projects." }, "default": { "description": "Error details", @@ -15882,41 +15682,31 @@ } } } - } - }, - "/oauth-tokens/{oauth_token_id}": { - "get": { + }, + "delete": { + "operationId": "deleteHyokCustomerKeyVersion", + "summary": "Delete HYOK Customer Key Version", + "description": "Delete a HYOK Customer Key Version. Can only be performed on unused key versions.\n\nThis operation is only available in HCP Terraform.", "tags": [ - "oauth-tokens" + "hyok" ], - "summary": "Show an OAuth Token", - "description": "Get details about an OAuth token.", - "operationId": "getOauthToken", "parameters": [ { - "name": "oauth_token_id", "in": "path", - "required": true, - "description": "The ID of the OAuth token.", + "name": "hyok_customer_key_version_id", "schema": { - "type": "string", - "example": "ot-xxxxxxxxxxxxxxxx" - } + "type": "string" + }, + "required": true, + "description": "HYOK Customer Key Version ID" } ], "responses": { - "200": { - "description": "OK", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/oauth-tokens-envelope" - } - } - } + "204": { + "description": "HYOK Customer Key Version deleted" }, - "404": { - "description": "Not Found", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -15926,94 +15716,46 @@ } } } - }, - "patch": { + } + }, + "/hyok-customer-key-versions/{hyok_customer_key_version_id}/actions/revoke": { + "x-vis": [ + "hcpt" + ], + "post": { + "operationId": "revokeHyokCustomerKeyVersion", + "summary": "Revoke HYOK Customer Key Version", + "description": "Revoke a HYOK Customer Key Version.\n\nThis operation is only available in HCP Terraform.", "tags": [ - "oauth-tokens" + "hyok" ], - "summary": "Update an OAuth Token", - "description": "Update an OAuth token by setting its SSH key.", - "operationId": "updateOauthToken", "parameters": [ { - "name": "oauth_token_id", "in": "path", - "required": true, - "description": "The ID of the OAuth token.", + "name": "hyok_customer_key_version_id", "schema": { - "type": "string", - "example": "ot-xxxxxxxxxxxxxxxx" - } + "type": "string" + }, + "required": true, + "description": "HYOK Customer Key Version ID" } ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/oauth-tokens-envelope" - } - } - } - }, "responses": { - "200": { - "description": "OK", + "202": { + "description": "HYOK Key Version revocation initiated", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/oauth-tokens-envelope" + "type": "string", + "enum": [ + "null" + ] } } } }, - "404": { - "description": "Not Found", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - }, - "422": { - "description": "Unprocessable Content", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } - } - } - } - }, - "delete": { - "tags": [ - "oauth-tokens" - ], - "summary": "Destroy an OAuth Token", - "description": "Destroy an OAuth token.", - "operationId": "deleteOauthToken", - "parameters": [ - { - "name": "oauth_token_id", - "in": "path", - "required": true, - "description": "The ID of the OAuth token.", - "schema": { - "type": "string", - "example": "ot-xxxxxxxxxxxxxxxx" - } - } - ], - "responses": { - "204": { - "description": "No Content" - }, - "404": { - "description": "Not Found", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -16025,74 +15767,41 @@ } } }, - "/organizations/{organization_name}/oauth-tokens": { + "/hyok-encrypted-data-keys/{hyok_encrypted_data_key_id}": { + "x-vis": [ + "hcpt" + ], "get": { + "operationId": "getHyokEncryptedDataKey", + "summary": "Get HYOK Encrypted Data Key details", + "description": "Get details about a HYOK Encrypted Data Key\n\nThis operation is only available in HCP Terraform.", "tags": [ - "oauth-tokens" + "hyok" ], - "summary": "List OAuth Tokens for an Organization", - "description": "List all OAuth tokens for a given organization.", - "operationId": "listOauthTokensForOrganization", "parameters": [ { - "name": "organization_name", "in": "path", - "required": true, - "description": "The name of the organization.", - "schema": { - "type": "string", - "example": "my-organization" - } - }, - { - "name": "filter[provider]", - "in": "query", - "required": false, - "description": "Filter tokens by VCS provider name.", + "name": "hyok_encrypted_data_key_id", "schema": { - "type": "string", - "example": "github" - } - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "type": "string" + }, + "required": true, + "description": "HYOK Encrypted Data Key ID" } ], "responses": { "200": { - "description": "OK", + "description": "HYOK Encrypted Data Key details", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/oauth-tokens" - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - } - } + "$ref": "#/components/schemas/hyok-encrypted-data-keys-envelope" } } } }, - "404": { - "description": "Not Found", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -16104,64 +15813,41 @@ } } }, - "/oauth-clients/{oauth_client_id}/oauth-tokens": { + "/oidc-configurations/{oidc_configuration_id}": { + "x-vis": [ + "hcpt" + ], "get": { + "operationId": "getOidcConfiguration", + "summary": "Get OIDC Configuration details", + "description": "Get details about an OIDC configuration\n\nThis operation is only available in HCP Terraform.", "tags": [ - "oauth-tokens" + "hyok" ], - "summary": "List OAuth Tokens for an OAuth Client", - "description": "List all OAuth tokens for a given OAuth client.", - "operationId": "listOauthTokensForOauthClient", "parameters": [ { - "name": "oauth_client_id", "in": "path", - "required": true, - "description": "The ID of the OAuth client.", + "name": "oidc_configuration_id", "schema": { - "type": "string", - "example": "oc-xxxxxxxxxxxxxxxx" - } - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "type": "string" + }, + "required": true, + "description": "OIDC Configuration ID" } ], "responses": { "200": { - "description": "OK", + "description": "OIDC Configuration details", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/oauth-tokens" - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - } - } + "$ref": "#/components/schemas/oidc-configuration-envelope" } } } }, - "404": { - "description": "Not Found", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -16171,74 +15857,48 @@ } } } - } - }, - "/oauth-tokens/{oauth_token_id}/authorized-repos": { - "get": { + }, + "patch": { + "operationId": "updateOidcConfiguration", + "summary": "Update OIDC Configuration", + "description": "Update an OIDC configuration\n\nThis operation is only available in HCP Terraform.", "tags": [ - "oauth-tokens" + "hyok" ], - "summary": "List Authorized Repositories for an OAuth Token", - "description": "List all repositories that the OAuth token is authorized to access.", - "operationId": "listAuthorizedReposForOauthToken", "parameters": [ { - "name": "oauth_token_id", "in": "path", - "required": true, - "description": "The ID of the OAuth token.", - "schema": { - "type": "string", - "example": "ot-xxxxxxxxxxxxxxxx" - } - }, - { - "name": "organization", - "in": "query", - "required": false, - "description": "The VCS organization name to scope repositories to. Required for Azure DevOps providers.", + "name": "oidc_configuration_id", "schema": { "type": "string" - } - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + }, + "required": true, + "description": "OIDC Configuration ID" } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/oidc-configuration-envelope" + } + } + } + }, "responses": { "200": { - "description": "OK", + "description": "OIDC Configuration updated", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/authorized-repos" - } - }, - "meta": { - "type": "object", - "properties": { - "next-page": { - "type": "integer", - "nullable": true, - "description": "The next page number, if more pages are available." - } - } - } - } + "$ref": "#/components/schemas/oidc-configuration-envelope" } } } }, - "404": { - "description": "Not Found", + "default": { + "description": "Error details", "content": { "application/vnd.api+json": { "schema": { @@ -16250,47 +15910,38 @@ } } }, - "/oauth-tokens/{oauth_token_id}/vcs-organizations": { + "/authentication-tokens/{id}": { "get": { + "operationId": "getAuthenticationToken", + "summary": "Get authentication token details", + "description": "Get details about an authentication token", "tags": [ - "oauth-tokens" + "authentication-tokens" ], - "summary": "List VCS Organizations for an OAuth Token", - "description": "List all VCS organizations accessible via the OAuth token. Only applicable to Azure DevOps providers.", - "operationId": "listVcsOrganizationsForOauthToken", "parameters": [ { - "name": "oauth_token_id", "in": "path", - "required": true, - "description": "The ID of the OAuth token.", + "name": "id", "schema": { - "type": "string", - "example": "ot-xxxxxxxxxxxxxxxx" - } + "type": "string" + }, + "required": true, + "description": "ID - Can be a token ID or a team ID, depending on the token type" } ], "responses": { "200": { - "description": "OK", + "description": "Authentication Token details", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/vcs-organization" - } - } - } + "$ref": "#/components/schemas/authentication-tokens-envelope" } } } }, - "404": { - "description": "Not Found", + "default": { + "description": "Error Details", "content": { "application/vnd.api+json": { "schema": { @@ -16300,68 +15951,42 @@ } } } - } - }, - "/github-app-installations": { - "get": { - "operationId": "listGithubAppInstallations", - "summary": "List GitHub App Installations", - "description": "List GitHub App installations available to the current user.", + }, + "post": { + "operationId": "createAuthenticationToken", + "summary": "Create Authentication Token", + "description": "Create an authentication token", "tags": [ - "github-app-installations" + "authentication-tokens" ], "parameters": [ { - "in": "query", - "name": "filter[name]", - "schema": { - "type": "string" - }, - "required": false, - "description": "Filter by GitHub organization or login name." - }, - { - "in": "query", - "name": "filter[installation_id]", + "in": "path", + "name": "id", "schema": { "type": "string" }, - "required": false, - "description": "Filter by GitHub installation ID." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "required": true, + "description": "ID - Can be a token ID or a team ID, depending on the token type" } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/authentication-tokens-envelope" + } + } + } + }, "responses": { - "200": { - "description": "List of GitHub App installations", + "201": { + "description": "Authentication token created", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/github-app-installations" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } + "$ref": "#/components/schemas/authentication-tokens-envelope" } } } @@ -16377,62 +16002,28 @@ } } } - } - }, - "/github-app-installations/{github_app_installation_id}/repos": { - "get": { - "operationId": "listGithubAppInstallationRepos", - "summary": "List GitHub App Installation Repositories", - "description": "List repositories accessible through a GitHub App installation.", + }, + "delete": { + "operationId": "deleteAuthenticationToken", + "summary": "Delete authentication Token", + "description": "Delete an authentication token", "tags": [ - "github-app-installations" + "authentication-tokens" ], "parameters": [ { "in": "path", - "name": "github_app_installation_id", + "name": "id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the GitHub App installation." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "ID - Can be a token ID or a team ID, depending on the token type" } ], "responses": { - "200": { - "description": "List of repositories", - "content": { - "application/vnd.api+json": { - "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/github-app-repos" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } - } - } - } + "204": { + "description": "Authentication token deleted" }, "default": { "description": "Error details", @@ -16447,32 +16038,32 @@ } } }, - "/github-app/installation/{github_app_installation_id}": { + "/users/{user_id}": { "get": { - "operationId": "getGithubAppInstallation", - "summary": "Show GitHub App Installation", - "description": "Get details about a GitHub App installation.", + "operationId": "showUser", + "summary": "Show User", + "description": "Shows details for a given user.", "tags": [ - "github-app-installations" + "users" ], "parameters": [ { "in": "path", - "name": "github_app_installation_id", + "name": "user_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the GitHub App installation." + "description": "The ID of the desired user." } ], "responses": { "200": { - "description": "GitHub App installation details", + "description": "User details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/github-app-installations-envelope" + "$ref": "#/components/schemas/users-envelope" } } } @@ -16490,32 +16081,23 @@ } } }, - "/github-app/installations": { + "/users/{user_id}/github-app-oauth-tokens": { "get": { - "operationId": "listGithubAppInstallationsForCurrentUser", - "summary": "List GitHub App Installations for Current User", - "description": "List GitHub App installations accessible to the current authenticated user.", + "operationId": "listUserGithubAppOauthTokens", + "summary": "List User GitHub App OAuth Tokens", + "description": "List GitHub App OAuth tokens for a given user.", "tags": [ - "github-app-installations" + "users" ], "parameters": [ { - "in": "query", - "name": "filter[name]", - "schema": { - "type": "string" - }, - "required": false, - "description": "Filter by GitHub organization or login name." - }, - { - "in": "query", - "name": "filter[installation_id]", + "in": "path", + "name": "user_id", "schema": { "type": "string" }, - "required": false, - "description": "Filter by GitHub installation ID." + "required": true, + "description": "The ID of the user." }, { "$ref": "#/components/parameters/page_number" @@ -16526,7 +16108,7 @@ ], "responses": { "200": { - "description": "List of GitHub App installations", + "description": "GitHub App OAuth tokens", "content": { "application/vnd.api+json": { "schema": { @@ -16535,9 +16117,12 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/github-app-installations" + "$ref": "#/components/schemas/github-app-oauth-tokens" } }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, "meta": { "type": "object", "properties": { @@ -16545,9 +16130,6 @@ "$ref": "#/components/schemas/pagination" } } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" } } } @@ -16567,23 +16149,23 @@ } } }, - "/organizations/{organization_name}/github-app-installations": { + "/users/{user_id}/authentication-tokens": { "get": { - "operationId": "listOrganizationGithubAppInstallations", - "summary": "List Organization GitHub App Installations", - "description": "List GitHub App installations linked to an organization.", + "operationId": "listUserTokens", + "summary": "List User Tokens", + "description": "List all tokens for a specified user", "tags": [ - "github-app-installations" + "authentication-tokens" ], "parameters": [ { "in": "path", - "name": "organization_name", + "name": "user_id", "schema": { "type": "string" }, "required": true, - "description": "The name of the organization." + "description": "User ID" }, { "$ref": "#/components/parameters/page_number" @@ -16594,7 +16176,7 @@ ], "responses": { "200": { - "description": "List of GitHub App installations", + "description": "Success", "content": { "application/vnd.api+json": { "schema": { @@ -16603,9 +16185,12 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/github-app-installations" + "$ref": "#/components/schemas/authentication-tokens" } }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, "meta": { "type": "object", "properties": { @@ -16613,9 +16198,6 @@ "$ref": "#/components/schemas/pagination" } } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" } } } @@ -16633,55 +16215,100 @@ } } } - } - }, - "/organizations/{organization_name}/github-app-installations/{github_app_installation_id}/repos": { - "get": { - "operationId": "listOrganizationGithubAppInstallationRepos", - "summary": "List Organization GitHub App Installation Repositories", - "description": "List repositories accessible through a GitHub App installation linked to an organization.", + }, + "post": { + "operationId": "createUserToken", + "summary": "Create User Token", + "description": "Create a user token", "tags": [ - "github-app-installations" + "authentication-tokens" ], "parameters": [ { "in": "path", - "name": "organization_name", - "schema": { - "type": "string" - }, - "required": true, - "description": "The name of the organization." - }, - { - "in": "path", - "name": "github_app_installation_id", + "name": "user_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the GitHub App installation." - }, - { - "$ref": "#/components/parameters/page_number" - }, - { - "$ref": "#/components/parameters/page_size" + "description": "User ID" } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/authentication-tokens-envelope" + } + } + } + }, "responses": { - "200": { - "description": "List of repositories", + "201": { + "description": "User token created", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/github-app-repos" - } + "$ref": "#/components/schemas/authentication-tokens-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/agent-pools/{agent_pool_id}/authentication-tokens": { + "get": { + "operationId": "listAgentTokens", + "summary": "List Agent Tokens", + "description": "List all tokens for the specified agent pool.", + "tags": [ + "authentication-tokens" + ], + "parameters": [ + { + "in": "path", + "name": "agent_pool_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the Agent Pool" + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/authentication-tokens" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" }, "meta": { "type": "object", @@ -16690,9 +16317,6 @@ "$ref": "#/components/schemas/pagination" } } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" } } } @@ -16710,39 +16334,75 @@ } } } - } - }, - "/organizations/{organization_name}/github-app-installations/{github_app_installation_id}/link-account": { + }, "post": { - "operationId": "linkOrganizationGithubAppInstallation", - "summary": "Link GitHub App Installation to Organization", - "description": "Link a GitHub App installation to an organization.", + "operationId": "createAgentToken", + "summary": "Create Agent Token", + "description": "Create an agent token", "tags": [ - "github-app-installations" + "authentication-tokens" ], "parameters": [ { "in": "path", - "name": "organization_name", - "schema": { - "type": "string" - }, - "required": true, - "description": "The name of the organization." - }, - { - "in": "path", - "name": "github_app_installation_id", + "name": "agent_pool_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the GitHub App installation." + "description": "The ID of the Agent Pool" } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/authentication-tokens-envelope" + } + } + } + }, "responses": { - "204": { - "description": "No Content" + "201": { + "description": "Agent token created", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/authentication-tokens-envelope" + } + } + } + }, + "404": { + "description": "Agent Pool not found or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Malformed request body (missing attributes, wrong types, etc.)", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "500": { + "description": "Failure during Agent Token creation", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } }, "default": { "description": "Error details", @@ -16757,13 +16417,13 @@ } } }, - "/tasks/{id}": { + "/teams/{id}/authentication-token": { "get": { - "operationId": "getTask", - "summary": "Get a Run Task", - "description": "Get details about a run task.", + "operationId": "getAuthenticationToken", + "summary": "Get authentication token details", + "description": "Get details about an authentication token", "tags": [ - "run-tasks" + "authentication-tokens" ], "parameters": [ { @@ -16773,31 +16433,22 @@ "type": "string" }, "required": true, - "description": "The ID of the run task." - }, - { - "in": "query", - "name": "include", - "schema": { - "type": "string" - }, - "required": false, - "description": "Allows including related resource data. Value must be a comma-separated list containing one or more of `workspace_tasks` or `workspace_tasks.workspace`.\n" + "description": "ID - Can be a token ID or a team ID, depending on the token type" } ], "responses": { "200": { - "description": "Run task details", + "description": "Authentication Token details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/tasks-envelope" + "$ref": "#/components/schemas/authentication-tokens-envelope" } } } }, "default": { - "description": "Error details", + "description": "Error Details", "content": { "application/vnd.api+json": { "schema": { @@ -16808,12 +16459,12 @@ } } }, - "patch": { - "operationId": "updateTask", - "summary": "Update a Run Task", - "description": "Update a run task.", + "post": { + "operationId": "createAuthenticationToken", + "summary": "Create Authentication Token", + "description": "Create an authentication token", "tags": [ - "run-tasks" + "authentication-tokens" ], "parameters": [ { @@ -16823,7 +16474,7 @@ "type": "string" }, "required": true, - "description": "The ID of the run task." + "description": "ID - Can be a token ID or a team ID, depending on the token type" } ], "requestBody": { @@ -16831,18 +16482,18 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/tasks-envelope" + "$ref": "#/components/schemas/authentication-tokens-envelope" } } } }, "responses": { - "200": { - "description": "Run task updated", + "201": { + "description": "Authentication token created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/tasks-envelope" + "$ref": "#/components/schemas/authentication-tokens-envelope" } } } @@ -16860,11 +16511,11 @@ } }, "delete": { - "operationId": "deleteTask", - "summary": "Delete a Run Task", - "description": "Delete a run task.", + "operationId": "deleteAuthenticationToken", + "summary": "Delete authentication Token", + "description": "Delete an authentication token", "tags": [ - "run-tasks" + "authentication-tokens" ], "parameters": [ { @@ -16874,12 +16525,12 @@ "type": "string" }, "required": true, - "description": "The ID of the run task." + "description": "ID - Can be a token ID or a team ID, depending on the token type" } ], "responses": { "204": { - "description": "Run task deleted" + "description": "Authentication token deleted" }, "default": { "description": "Error details", @@ -16894,32 +16545,27 @@ } } }, - "/organizations/{organization_name}/tasks": { + "/organization/audit-trail": { + "x-vis": [ + "hcpt" + ], "get": { - "operationId": "listOrganizationTasks", - "summary": "List Run Tasks", - "description": "List all run tasks in an organization.", + "operationId": "showOrganizationAuditTrail", + "summary": "List organization audit events", + "description": "Returns a list of audit events for the organization associated with the authentication token. HCP Terraform retains 14 days of audit log information. Unlike most HCP Terraform APIs, this endpoint does not use the JSON:API specification. This endpoint requires an organization token or an audit trail token; user tokens and team tokens are not accepted.\n\nThis operation is only available in HCP Terraform.", "tags": [ - "run-tasks" + "audit-trails" ], "parameters": [ - { - "in": "path", - "name": "organization_name", - "schema": { - "type": "string" - }, - "required": true, - "description": "The name of the organization." - }, { "in": "query", - "name": "include", + "name": "since", "schema": { - "type": "string" + "type": "string", + "format": "date-time" }, "required": false, - "description": "Allows including related resource data. Value must be a comma-separated list containing one or more of `workspace_tasks` or `workspace_tasks.workspace`.\n" + "description": "Returns only audit events created after this date. Must be a UTC ISO8601 datetime string (YYYY-MM-DDTHH:MM:SS.SSSZ)." }, { "$ref": "#/components/parameters/page_number" @@ -16930,52 +16576,190 @@ ], "responses": { "200": { - "description": "List of run tasks", + "description": "Audit events list", "content": { - "application/vnd.api+json": { + "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/tasks" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - } - } - } - } - } - }, - "default": { - "description": "Error details", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/errors" - } - } + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The ID of this audit event." + }, + "version": { + "type": "string", + "description": "The audit trail schema version." + }, + "type": { + "type": "string", + "description": "The type of audit event (defaults to \"Resource\")." + }, + "timestamp": { + "type": "string", + "format": "date-time", + "description": "UTC ISO8601 timestamp of the event." + }, + "auth": { + "type": "object", + "properties": { + "accessor_id": { + "type": "string", + "description": "The ID of the audited actor." + }, + "description": { + "type": "string", + "nullable": true, + "description": "Username of the audited actor." + }, + "type": { + "type": "string", + "nullable": true, + "description": "Authentication type. One of \"Client\", \"Impersonated\", or \"System\"." + }, + "impersonator_id": { + "type": "string", + "nullable": true, + "description": "The ID of the impersonating actor, if available." + }, + "organization_id": { + "type": "string", + "description": "The ID of the organization." + } + } + }, + "request": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true, + "description": "The ID of the request, if available." + } + } + }, + "resource": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The ID of the audited resource." + }, + "type": { + "type": "string", + "description": "The type of the audited resource (e.g., \"run\")." + }, + "action": { + "type": "string", + "description": "The action that was audited (e.g., \"applied\")." + }, + "meta": { + "type": "object", + "nullable": true, + "additionalProperties": true, + "description": "Key-value metadata about the audited event. Defaults to null." + } + } + } + } + } + }, + "pagination": { + "type": "object", + "properties": { + "current_page": { + "type": "integer" + }, + "page_size": { + "type": "integer" + }, + "prev_page": { + "type": "integer", + "nullable": true + }, + "next_page": { + "type": "integer", + "nullable": true + }, + "total_pages": { + "type": "integer" + }, + "total_count": { + "type": "integer" + } + } + } + } + } + } + } + }, + "default": { + "description": "Unauthorized or forbidden", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/organizations/{organization_name}/authentication-token": { + "get": { + "operationId": "getOrganizationToken", + "summary": "Get organization token details", + "description": "Get details about an organization token", + "tags": [ + "authentication-tokens" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "Organization name" + } + ], + "responses": { + "200": { + "description": "Organization Token details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/authentication-tokens-envelope" + } + } + } + }, + "default": { + "description": "Error Details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } } } } }, "post": { - "operationId": "createTask", - "summary": "Create a Run Task", - "description": "Create a run task in an organization.", + "operationId": "createOrganizationToken", + "summary": "Create Organization Token", + "description": "Create an organization token", "tags": [ - "run-tasks" + "authentication-tokens" ], "parameters": [ { @@ -16985,7 +16769,7 @@ "type": "string" }, "required": true, - "description": "The name of the organization." + "description": "Organization name" } ], "requestBody": { @@ -16993,21 +16777,55 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/tasks-envelope" + "$ref": "#/components/schemas/authentication-tokens-envelope" } } } }, "responses": { "201": { - "description": "Run task created", + "description": "Organization token created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/tasks-envelope" + "$ref": "#/components/schemas/authentication-tokens-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } + } + } + }, + "delete": { + "operationId": "deleteOrganizationToken", + "summary": "Delete organization Token", + "description": "Delete an organization token", + "tags": [ + "authentication-tokens" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "Organization name" + } + ], + "responses": { + "204": { + "description": "Organization token deleted" }, "default": { "description": "Error details", @@ -17022,23 +16840,23 @@ } } }, - "/tasks/{id}/relationships/workspace-tasks": { + "/organizations/{organization_name}/team-tokens": { "get": { - "operationId": "listTaskWorkspaceTasks", - "summary": "List Workspace Run Tasks for a Run Task", - "description": "List all workspace run tasks associated with a run task.", + "operationId": "listTeamTokensForAnOrganization", + "summary": "List Team Tokens for an Organization", + "description": "List all tokens for a specified organization", "tags": [ - "run-tasks" + "authentication-tokens" ], "parameters": [ { "in": "path", - "name": "id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the run task." + "description": "Organization Name" }, { "$ref": "#/components/parameters/page_number" @@ -17049,7 +16867,7 @@ ], "responses": { "200": { - "description": "List of workspace run tasks", + "description": "Success", "content": { "application/vnd.api+json": { "schema": { @@ -17058,9 +16876,12 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/workspace-tasks" + "$ref": "#/components/schemas/authentication-tokens" } }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, "meta": { "type": "object", "properties": { @@ -17068,9 +16889,6 @@ "$ref": "#/components/schemas/pagination" } } - }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" } } } @@ -17090,26 +16908,57 @@ } } }, - "/workspaces/{workspace_id}/tasks": { + "/organizations/{organization_name}/teams": { "get": { - "operationId": "listWorkspaceTasks", - "summary": "List Workspace Run Tasks", - "description": "List all run tasks associated with a workspace.", + "operationId": "listTeams", + "summary": "List Teams", + "description": "List teams in an organization. Any member of an organization can view visible teams and any secret teams they are a member of.", "tags": [ - "run-tasks" + "teams" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the workspace." - }, - { - "$ref": "#/components/parameters/page_number" + "description": "Name of the organization" + }, + { + "in": "query", + "name": "q", + "schema": { + "type": "string" + }, + "required": false, + "description": "A search query string. Teams are searchable by name (case-insensitive)." + }, + { + "in": "query", + "name": "filter[names]", + "schema": { + "type": "string" + }, + "required": false, + "description": "If specified, restricts results to a team with a matching name. If multiple comma separated values are specified, teams matching any of the names are returned." + }, + { + "in": "query", + "name": "include", + "schema": { + "type": "string", + "enum": [ + "users", + "organization-memberships" + ] + }, + "required": false, + "description": "Optionally side-load relationships. Can include \"users\" or \"organization-memberships\"." + }, + { + "$ref": "#/components/parameters/page_number" }, { "$ref": "#/components/parameters/page_size" @@ -17117,16 +16966,19 @@ ], "responses": { "200": { - "description": "List of workspace run tasks", + "description": "Teams list", "content": { "application/vnd.api+json": { "schema": { "type": "object", + "required": [ + "data" + ], "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/workspace-tasks" + "$ref": "#/components/schemas/teams" } }, "meta": { @@ -17139,12 +16991,45 @@ }, "links": { "$ref": "#/components/schemas/self-with-pagination" + }, + "included": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/users" + }, + { + "$ref": "#/components/schemas/organization-memberships" + } + ] + } } } } } } }, + "400": { + "description": "Invalid include parameter", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "404": { + "description": "Organization not found, or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, "default": { "description": "Error details", "content": { @@ -17158,21 +17043,21 @@ } }, "post": { - "operationId": "createWorkspaceTask", - "summary": "Associate a Run Task to a Workspace", - "description": "Associate an existing run task to a workspace.", + "operationId": "createTeam", + "summary": "Create Team", + "description": "Create a team in an organization.", "tags": [ - "run-tasks" + "teams" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "organization_name", "schema": { "type": "string" }, "required": true, - "description": "The ID of the workspace." + "description": "Name of the organization" } ], "requestBody": { @@ -17180,18 +17065,48 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspace-tasks-envelope" + "$ref": "#/components/schemas/teams-envelope" } } } }, "responses": { - "201": { - "description": "Workspace run task created", + "200": { + "description": "Team created successfully", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspace-tasks-envelope" + "$ref": "#/components/schemas/teams-envelope" + } + } + } + }, + "400": { + "description": "Invalid include parameter", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "404": { + "description": "Organization not found, or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Malformed request body (missing attributes, wrong types, etc.)", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -17209,41 +17124,87 @@ } } }, - "/workspaces/{workspace_id}/tasks/{id}": { + "/teams/{team_id}": { "get": { - "operationId": "getWorkspaceTask", - "summary": "Show a Workspace Run Task", - "description": "Get details about a workspace run task.", + "operationId": "getTeam", + "summary": "Show Team Information", + "description": "Get details about a team.", "tags": [ - "run-tasks" + "teams" ], "parameters": [ { "in": "path", - "name": "workspace_id", + "name": "team_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the workspace." + "description": "Team ID" }, { - "in": "path", - "name": "id", + "in": "query", + "name": "include", "schema": { - "type": "string" + "type": "string", + "enum": [ + "users", + "organization-memberships" + ] }, - "required": true, - "description": "The ID of the workspace run task." + "required": false, + "description": "Optionally side-load relationships. Can include \"users\" or \"organization-memberships\"." } ], "responses": { "200": { - "description": "Workspace run task details", + "description": "Team details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspace-tasks-envelope" + "allOf": [ + { + "$ref": "#/components/schemas/teams-envelope" + }, + { + "type": "object", + "properties": { + "included": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/users" + }, + { + "$ref": "#/components/schemas/organization-memberships" + } + ] + } + } + } + } + ] + } + } + } + }, + "400": { + "description": "Invalid include parameter", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "404": { + "description": "Team not found, or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -17261,30 +17222,21 @@ } }, "patch": { - "operationId": "updateWorkspaceTask", - "summary": "Update a Workspace Run Task", - "description": "Update a workspace run task.", + "operationId": "updateTeam", + "summary": "Update Team", + "description": "Update a team's attributes.", "tags": [ - "run-tasks" + "teams" ], "parameters": [ { "in": "path", - "name": "workspace_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the workspace." - }, - { - "in": "path", - "name": "id", + "name": "team_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the workspace run task." + "description": "Team ID" } ], "requestBody": { @@ -17292,18 +17244,48 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspace-tasks-envelope" + "$ref": "#/components/schemas/teams-envelope" } } } }, "responses": { "200": { - "description": "Workspace run task updated", + "description": "Team updated successfully", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspace-tasks-envelope" + "$ref": "#/components/schemas/teams-envelope" + } + } + } + }, + "400": { + "description": "Invalid include parameter", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "404": { + "description": "Team not found, or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Malformed request body (missing attributes, wrong types, etc.)", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -17321,35 +17303,36 @@ } }, "delete": { - "operationId": "deleteWorkspaceTask", - "summary": "Delete a Workspace Run Task", - "description": "Delete a workspace run task, dissociating the run task from the workspace.", + "operationId": "deleteTeam", + "summary": "Delete Team", + "description": "Delete a team. Only organization owners can delete teams.", "tags": [ - "run-tasks" + "teams" ], "parameters": [ { "in": "path", - "name": "workspace_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the workspace." - }, - { - "in": "path", - "name": "id", + "name": "team_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the workspace run task." + "description": "Team ID" } ], "responses": { "204": { - "description": "Workspace run task deleted" + "description": "Team deleted successfully" + }, + "404": { + "description": "Team not found, or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } }, "default": { "description": "Error details", @@ -17364,41 +17347,65 @@ } } }, - "/task-stages/{task_stage_id}": { - "get": { - "operationId": "getTaskStage", - "summary": "Show a Run Task Stage", - "description": "Get details about a specific run task stage.", + "/teams/{team_id}/relationships/users": { + "post": { + "operationId": "addTeamMembersByUsername", + "summary": "Add Users to Team (by username)", + "description": "Add multiple users to a team using their usernames. Both users and teams must already exist.", "tags": [ - "task-stages" + "teams" ], "parameters": [ { "in": "path", - "name": "task_stage_id", + "name": "team_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the task stage to show." - }, - { - "in": "query", - "name": "include", - "schema": { - "type": "string" - }, - "required": false, - "description": "A comma-separated list of related resources to include. Supported values: run, run.workspace, task-results, policy-evaluations." + "description": "The ID of the team." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/users-identifier-array-document" + } + } + } + }, "responses": { - "200": { - "description": "Task stage details", + "204": { + "description": "Users successfully added to team." + }, + "400": { + "description": "Invalid request (blank ID, wrong type, user does not exist, user is already a member, user is not in the organization).", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/task-stages-envelope" + "$ref": "#/components/schemas/errors" + } + } + } + }, + "403": { + "description": "Forbidden. The organization is managed by HCP.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "404": { + "description": "Team not found, or user unauthorized to perform action.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } @@ -17414,40 +17421,61 @@ } } } - } - }, - "/task-stages/{task_stage_id}/actions/override": { - "post": { - "operationId": "overrideTaskStage", - "summary": "Override a Task Stage", - "description": "Override a task stage that is in the awaiting_override status, allowing the run to continue even when run tasks have failed.", + }, + "delete": { + "operationId": "removeTeamMembersByUsername", + "summary": "Remove Users from Team (by username)", + "description": "Remove multiple users from a team using their usernames. This only removes users from this team; it does not delete the users from the organization.", "tags": [ - "task-stages" + "teams" ], "parameters": [ { "in": "path", - "name": "task_stage_id", + "name": "team_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the task stage to override." + "description": "The ID of the team." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/users-identifier-array-document" + } + } + } + }, "responses": { - "200": { - "description": "Task stage successfully overridden", + "204": { + "description": "Users successfully removed from team." + }, + "400": { + "description": "Invalid request (blank ID, wrong type, user is not a member).", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/task-stages-envelope" + "$ref": "#/components/schemas/errors" } } } }, - "409": { - "description": "The task stage is not in an overridable state or has no overridable failures.", + "403": { + "description": "Forbidden. The organization is managed by HCP, or attempting to remove the last owner of the owners team.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "404": { + "description": "Team not found, or user unauthorized to perform action.", "content": { "application/vnd.api+json": { "schema": { @@ -17469,23 +17497,63 @@ } } }, - "/runs/{run_id}/task-stages": { + "/teams/{team_id}/relationships/organization-memberships": { "get": { - "operationId": "listRunTaskStages", - "summary": "List the Run Task Stages in a Run", - "description": "List the run task stages associated with a run.", + "operationId": "listTeamOrganizationMemberships", + "summary": "List Team Organization Memberships", + "description": "List all organization memberships for a team. Returns both active members and invited users.", "tags": [ - "task-stages" + "teams" ], "parameters": [ { "in": "path", - "name": "run_id", + "name": "team_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the run to list task stages for." + "description": "The ID of the team." + }, + { + "in": "query", + "name": "filter[status]", + "schema": { + "type": "string", + "enum": [ + "active", + "invited", + "inactive" + ] + }, + "required": false, + "description": "Filter memberships by status." + }, + { + "in": "query", + "name": "filter[is_service_account]", + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ] + }, + "required": false, + "description": "Filter to include only service account members." + }, + { + "in": "query", + "name": "sort", + "schema": { + "type": "string", + "enum": [ + "status", + "-status" + ] + }, + "required": false, + "description": "Sort memberships. Prefix with '-' for descending order (e.g. '-status')." }, { "$ref": "#/components/parameters/page_number" @@ -17496,16 +17564,19 @@ ], "responses": { "200": { - "description": "List of run task stages", + "description": "List of organization memberships for the team.", "content": { "application/vnd.api+json": { "schema": { "type": "object", + "required": [ + "data" + ], "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/task-stages" + "$ref": "#/components/schemas/organization-memberships" } }, "meta": { @@ -17524,8 +17595,8 @@ } } }, - "default": { - "description": "Error details", + "400": { + "description": "Invalid filter or sort parameter.", "content": { "application/vnd.api+json": { "schema": { @@ -17533,36 +17604,13 @@ } } } - } - } - } - }, - "/task-results/{task_result_id}": { - "get": { - "operationId": "getTaskResult", - "summary": "Show a Run Task Result", - "description": "Get details about a specific run task result.", - "tags": [ - "task-stages" - ], - "parameters": [ - { - "in": "path", - "name": "task_result_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the task result to show." - } - ], - "responses": { - "200": { - "description": "Task result details", + }, + "404": { + "description": "Team not found, or user unauthorized to perform action.", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/task-results-envelope" + "$ref": "#/components/schemas/errors" } } } @@ -17578,41 +17626,61 @@ } } } - } - }, - "/task-results/{task_result_id}/body": { - "get": { - "operationId": "getTaskResultBody", - "summary": "Download Task Result Body", - "description": "Download the body content of a native task result. This endpoint redirects to a \npre-signed URL for downloading the task result data stored in object storage.\n", + }, + "post": { + "operationId": "addTeamMembersByOrgMembership", + "summary": "Add Users to Team (by organization membership ID)", + "description": "Add multiple users to a team using their organization membership IDs. Unlike the username method, users only need a pending invitation to the organization.", "tags": [ - "task-stages" + "teams" ], "parameters": [ { "in": "path", - "name": "task_result_id", + "name": "team_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the task result." + "description": "The ID of the team." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/organization-memberships-identifier-array-document" + } + } + } + }, "responses": { - "302": { - "description": "Redirect to download URL", - "headers": { - "Location": { - "description": "Pre-signed URL for downloading the task result body", + "204": { + "description": "Users successfully added to team." + }, + "400": { + "description": "Invalid request (blank ID, wrong type, membership does not exist, user is already a member, user is not in the organization).", + "content": { + "application/vnd.api+json": { "schema": { - "type": "string" + "$ref": "#/components/schemas/errors" + } + } + } + }, + "403": { + "description": "Forbidden. The organization is managed by HCP.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" } } } }, "404": { - "description": "Task result not found or has no body content", + "description": "Team not found, or user unauthorized to perform action.", "content": { "application/vnd.api+json": { "schema": { @@ -17632,34 +17700,23 @@ } } } - } - }, - "/task-results/{task_result_id}/callback": { - "patch": { - "operationId": "callbackTaskResult", - "summary": "Update a Run Task Result", - "description": "Update a run task result with status, message, and optional outcome data. This endpoint is used by run task integrations to report execution results back to HCP Terraform. Requires a url_code query parameter for authentication.", + }, + "delete": { + "operationId": "removeTeamMembersByOrgMembership", + "summary": "Remove Users from Team (by organization membership ID)", + "description": "Remove multiple users from a team using their organization membership IDs. This only removes users from this team; it does not delete the users from the organization.", "tags": [ - "task-stages" + "teams" ], "parameters": [ { "in": "path", - "name": "task_result_id", + "name": "team_id", "schema": { "type": "string" }, "required": true, - "description": "The ID of the task result to update." - }, - { - "in": "query", - "name": "url_code", - "schema": { - "type": "string" - }, - "required": false, - "description": "The callback authentication token issued to the run task integration. Required for run task integrations; not required for token-authenticated requests." + "description": "The ID of the team." } ], "requestBody": { @@ -17667,24 +17724,27 @@ "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/task-results-envelope" + "$ref": "#/components/schemas/organization-memberships-identifier-array-document" } } } }, "responses": { - "200": { - "description": "Task result updated successfully", + "204": { + "description": "Users successfully removed from team." + }, + "400": { + "description": "Invalid request (blank ID, wrong type, membership does not exist, user is not a member).", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/task-results-envelope" + "$ref": "#/components/schemas/errors" } } } }, - "409": { - "description": "The task result is in a terminal state and cannot be updated.", + "403": { + "description": "Forbidden. The organization is managed by HCP, or attempting to remove the last active owner of the owners team.", "content": { "application/vnd.api+json": { "schema": { @@ -17693,8 +17753,8 @@ } } }, - "422": { - "description": "Invalid attributes provided.", + "404": { + "description": "Team not found, or user unauthorized to perform action.", "content": { "application/vnd.api+json": { "schema": { @@ -17716,23 +17776,32 @@ } } }, - "/task-results/{task_result_id}/outcomes": { + "/team-projects": { "get": { - "operationId": "listTaskResultOutcomes", - "summary": "List the Outcomes for a Run Task Result", - "description": "List the run task result outcomes associated with a run task result.", + "operationId": "listTeamProjects", + "summary": "List Team Access to a Project", + "description": "List all team access grants for a project.", "tags": [ - "task-stages" + "team-projects" ], "parameters": [ { - "in": "path", - "name": "task_result_id", + "in": "query", + "name": "filter[project][id]", "schema": { "type": "string" }, "required": true, - "description": "The ID of the task result to list outcomes for." + "description": "The project ID to list team access for." + }, + { + "in": "query", + "name": "filter[team][id]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Optionally filter by team ID." }, { "$ref": "#/components/parameters/page_number" @@ -17743,7 +17812,7 @@ ], "responses": { "200": { - "description": "List of run task result outcomes", + "description": "List of team-project access grants", "content": { "application/vnd.api+json": { "schema": { @@ -17752,7 +17821,7 @@ "data": { "type": "array", "items": { - "$ref": "#/components/schemas/task-result-outcomes" + "$ref": "#/components/schemas/team-projects" } }, "meta": { @@ -17771,6 +17840,16 @@ } } }, + "404": { + "description": "Project not found or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, "default": { "description": "Error details", "content": { @@ -17782,40 +17861,37 @@ } } } - } - }, - "/task-result-outcomes/{task_result_outcome_id}": { - "get": { - "operationId": "getTaskResultOutcome", - "summary": "Show a Run Task Result Outcome", - "description": "Get details about a specific run task result outcome.", + }, + "post": { + "operationId": "addProjectTeamAccess", + "summary": "Add Team Access to a Project", + "description": "Add a team's access to a project.", "tags": [ - "task-stages" + "team-projects" ], - "parameters": [ - { - "in": "path", - "name": "task_result_outcome_id", - "schema": { - "type": "string" - }, - "required": true, - "description": "The ID of the task result outcome to show." + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/team-projects-envelope" + } + } } - ], + }, "responses": { - "200": { - "description": "Task result outcome details", + "201": { + "description": "Team access created", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/task-result-outcomes-envelope" + "$ref": "#/components/schemas/team-projects-envelope" } } } }, - "default": { - "description": "Error details", + "404": { + "description": "Project or team not found or user unauthorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -17823,49 +17899,13 @@ } } } - } - } - } - }, - "/workspace-transfers": { - "get": { - "operationId": "listWorkspaceTransfers", - "summary": "List Workspace Transfers", - "description": "List all workspace transfers you have access to.", - "tags": [ - "workspace-transfers" - ], - "parameters": [ - { - "$ref": "#/components/parameters/page_number" }, - { - "$ref": "#/components/parameters/page_size" - } - ], - "responses": { - "200": { - "description": "List of workspace transfers", + "422": { + "description": "Malformed request body (missing attributes, wrong types, etc.)", "content": { "application/vnd.api+json": { "schema": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/workspace-transfers" - } - }, - "meta": { - "type": "object", - "properties": { - "pagination": { - "$ref": "#/components/schemas/pagination" - } - } - } - } + "$ref": "#/components/schemas/errors" } } } @@ -17881,37 +17921,40 @@ } } } - }, - "post": { - "operationId": "createWorkspaceTransfer", - "summary": "Create a Workspace Transfer", - "description": "Queue a new workspace transfer across organizations.", + } + }, + "/team-projects/{team_project_id}": { + "get": { + "operationId": "showProjectTeamAccess", + "summary": "Show a Team Access Relationship", + "description": "Get details about a team's access to a project.", "tags": [ - "workspace-transfers" + "team-projects" ], - "requestBody": { - "required": true, - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/workspace-transfers-envelope" - } - } + "parameters": [ + { + "in": "path", + "name": "team_project_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the team/project relationship." } - }, + ], "responses": { - "201": { - "description": "Workspace transfer created", + "200": { + "description": "Team-project access details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspace-transfers-envelope" + "$ref": "#/components/schemas/team-projects-envelope" } } } }, - "422": { - "description": "Validation error", + "404": { + "description": "Team access not found or user unauthorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -17931,49 +17974,58 @@ } } } - } - }, - "/workspace-transfers/{workspace_transfer_id}": { - "get": { - "operationId": "getWorkspaceTransfer", - "summary": "Get Workspace Transfer details", - "description": "Get details about a workspace transfer.", + }, + "patch": { + "operationId": "updateProjectTeamAccess", + "summary": "Update Team Access to a Project", + "description": "Update a team's access level on a project.", "tags": [ - "workspace-transfers" + "team-projects" ], "parameters": [ { "in": "path", - "name": "workspace_transfer_id", + "name": "team_project_id", "schema": { "type": "string" }, "required": true, - "description": "Workspace Transfer ID" - }, - { - "in": "query", - "name": "include", - "schema": { - "type": "string" - }, - "required": false, - "description": "Related resources to include (e.g., operations)" + "description": "The ID of the team/project relationship." } ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/team-projects-envelope" + } + } + } + }, "responses": { "200": { - "description": "Workspace transfer details", + "description": "Team access updated successfully", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspace-transfers-envelope" + "$ref": "#/components/schemas/team-projects-envelope" } } } }, "404": { - "description": "Workspace transfer not found", + "description": "Team access not found or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Malformed request body (missing attributes, wrong types, etc.)", "content": { "application/vnd.api+json": { "schema": { @@ -17993,40 +18045,178 @@ } } } - } - }, - "/workspace-transfers/{workspace_transfer_id}/actions/resume": { - "post": { - "operationId": "resumeWorkspaceTransfer", - "summary": "Resume a Workspace Transfer", - "description": "Resume a paused workspace transfer. A transfer pauses automatically:\n- After data migration completes, awaiting approval before source workspace deletion (`awaiting_approval`)\n- If source workspace deletion times out (`source_workspace_deletion_stuck`)\nOnce resumed, the transfer proceeds with the remaining operations.\n", + }, + "delete": { + "operationId": "removeProjectTeamAccess", + "summary": "Remove Team Access from a Project", + "description": "Remove a team's access from a project.", "tags": [ - "workspace-transfers" + "team-projects" ], "parameters": [ { "in": "path", - "name": "workspace_transfer_id", + "name": "team_project_id", "schema": { "type": "string" }, "required": true, - "description": "Workspace Transfer ID" + "description": "The ID of the team/project relationship." + } + ], + "responses": { + "204": { + "description": "Team access removed successfully" + }, + "404": { + "description": "Team access not found or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/team-workspaces": { + "get": { + "operationId": "listTeamWorkspaces", + "summary": "List Team Access to a Workspace", + "description": "List all team access relationships. Optionally filter by workspace or team ID.", + "tags": [ + "team-access" + ], + "parameters": [ + { + "in": "query", + "name": "filter[workspace][id]", + "schema": { + "type": "string" + }, + "required": false, + "description": "The workspace ID to list team access for." + }, + { + "in": "query", + "name": "filter[team][id]", + "schema": { + "type": "string" + }, + "required": false, + "description": "The team ID to list workspace access for." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" } ], "responses": { "200": { - "description": "Workspace transfer resumed", + "description": "List of team access relationships", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspace-transfers-envelope" + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/team-workspaces" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } } } } }, - "409": { - "description": "Transfer is not paused", + "404": { + "description": "Workspace not found or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "post": { + "operationId": "addTeamAccess", + "summary": "Add Team Access to a Workspace", + "description": "Add a team's access to a workspace.", + "tags": [ + "team-access" + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/team-workspaces-envelope" + } + } + } + }, + "responses": { + "201": { + "description": "Team access relationship created", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/team-workspaces-envelope" + } + } + } + }, + "404": { + "description": "Workspace or Team not found or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Malformed request body (missing attributes, wrong types, etc.)", "content": { "application/vnd.api+json": { "schema": { @@ -18048,38 +18238,38 @@ } } }, - "/workspace-transfers/{workspace_transfer_id}/actions/cancel": { - "post": { - "operationId": "cancelWorkspaceTransfer", - "summary": "Cancel a Workspace Transfer", - "description": "Cancel a workspace transfer before the source workspace deletion begins.\nOnce the `remove_source_workspace` operation starts, the transfer cannot be canceled.\nCanceling leaves the source workspace intact but locked. You cannot resume a canceled transfer.\n", + "/team-workspaces/{team_workspace_id}": { + "get": { + "operationId": "showTeamAccess", + "summary": "Show a Team Access Relationship", + "description": "Get details about a team's access to a workspace.", "tags": [ - "workspace-transfers" + "team-access" ], "parameters": [ { "in": "path", - "name": "workspace_transfer_id", + "name": "team_workspace_id", "schema": { "type": "string" }, "required": true, - "description": "Workspace Transfer ID" + "description": "The team/workspace relationship ID." } ], "responses": { "200": { - "description": "Workspace transfer canceled", + "description": "Team access relationship details", "content": { "application/vnd.api+json": { "schema": { - "$ref": "#/components/schemas/workspace-transfers-envelope" + "$ref": "#/components/schemas/team-workspaces-envelope" } } } }, - "409": { - "description": "Transfer cannot be canceled (already started source workspace deletion, completed, or already canceled)", + "404": { + "description": "Team access not found or user unauthorized to perform action", "content": { "application/vnd.api+json": { "schema": { @@ -18099,248 +18289,7369 @@ } } } - } - } - }, - "components": { - "securitySchemes": { - "bearerAuth": { - "type": "http", - "scheme": "bearer" - } - }, - "schemas": { - "errors": { - "type": "object", - "properties": { - "errors": { - "type": "array", - "items": { - "type": "object", + }, + "patch": { + "operationId": "updateTeamAccess", + "summary": "Update Team Access to a Workspace", + "description": "Update a team's access to a workspace.", + "tags": [ + "team-access" + ], + "parameters": [ + { + "in": "path", + "name": "team_workspace_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The team/workspace relationship ID." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/team-workspaces-envelope" + } + } + } + }, + "responses": { + "200": { + "description": "Team access relationship updated", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/team-workspaces-envelope" + } + } + } + }, + "404": { + "description": "Team access not found or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Malformed request body (missing attributes, wrong types, etc.)", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "delete": { + "operationId": "removeTeamAccess", + "summary": "Remove Team Access to a Workspace", + "description": "Remove a team's access to a workspace.", + "tags": [ + "team-access" + ], + "parameters": [ + { + "in": "path", + "name": "team_workspace_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The team/workspace relationship ID." + } + ], + "responses": { + "204": { + "description": "Team access relationship deleted" + }, + "404": { + "description": "Team access not found or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/tasks/integrations": { + "get": { + "operationId": "listTaskIntegrations", + "tags": [ + "tasks" + ], + "summary": "List Integrations", + "description": "List all available integrations that can be used with tasks. \nBy default, only active integrations are returned.\n", + "parameters": [ + { + "name": "search", + "in": "query", + "required": false, + "description": "Search integrations by name (case-insensitive, partial match).", + "schema": { + "type": "string", + "example": "cloud" + } + }, + { + "name": "category", + "in": "query", + "required": false, + "description": "Filter integrations by category.", + "schema": { + "type": "string", + "example": "cost-estimation" + } + }, + { + "name": "include_inactive", + "in": "query", + "required": false, + "description": "Include inactive integrations in the results.", + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ], + "default": "false" + } + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/integrations" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/workspaces/{workspace_id}/configuration-versions": { + "get": { + "operationId": "listConfigurationVersions", + "summary": "List Configuration Versions", + "description": "List configuration versions for a workspace.", + "tags": [ + "configuration-versions" + ], + "parameters": [ + { + "in": "path", + "name": "workspace_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the workspace." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of configuration versions", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/configuration-versions" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "post": { + "operationId": "createConfigurationVersion", + "summary": "Create Configuration Version", + "description": "Create a new configuration version in a workspace.", + "tags": [ + "configuration-versions" + ], + "parameters": [ + { + "in": "path", + "name": "workspace_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the workspace." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/configuration-versions-envelope" + } + } + } + }, + "responses": { + "201": { + "description": "Configuration version created", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/configuration-versions-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/configuration-versions/{configuration_version_id}": { + "get": { + "operationId": "getConfigurationVersion", + "summary": "Get Configuration Version", + "description": "Get details of a specific configuration version.", + "tags": [ + "configuration-versions" + ], + "parameters": [ + { + "in": "path", + "name": "configuration_version_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the configuration version." + } + ], + "responses": { + "200": { + "description": "Configuration version details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/configuration-versions-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/configuration-versions/{configuration_version_id}/ingress-attributes": { + "get": { + "operationId": "getIngressAttributes", + "summary": "Get Ingress Attributes", + "description": "Get commit information for a configuration version.", + "tags": [ + "configuration-versions" + ], + "parameters": [ + { + "in": "path", + "name": "configuration_version_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the configuration version." + } + ], + "responses": { + "200": { + "description": "Ingress attributes details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/ingress-attributes" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/configuration-versions/{configuration_version_id}/actions/archive": { + "post": { + "operationId": "archiveConfigurationVersion", + "summary": "Archive Configuration Version", + "description": "Archive the uploaded files for a configuration version.", + "tags": [ + "configuration-versions" + ], + "parameters": [ + { + "in": "path", + "name": "configuration_version_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the configuration version." + } + ], + "responses": { + "202": { + "description": "Archive process initiated", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "string", + "enum": [ + "null" + ] + } + } + } + }, + "409": { + "description": "Configuration version was in a non-archivable state or the configuration version was created with VCS and cannot be archived through the API.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/configuration-versions/{configuration_version_id}/actions/soft_delete_backing_data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "softDeleteConfigurationVersion", + "summary": "Soft Delete Configuration Version", + "description": "Mark a configuration version for garbage collection.\n\nThis operation is only available in Terraform Enterprise.", + "tags": [ + "configuration-versions" + ], + "parameters": [ + { + "in": "path", + "name": "configuration_version_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the configuration version." + } + ], + "responses": { + "200": { + "description": "Configuration version marked for garbage collection" + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/configuration-versions/{configuration_version_id}/actions/restore_backing_data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "restoreConfigurationVersion", + "summary": "Restore Configuration Version", + "description": "Restore a configuration version marked for garbage collection.\n\nThis operation is only available in Terraform Enterprise.", + "tags": [ + "configuration-versions" + ], + "parameters": [ + { + "in": "path", + "name": "configuration_version_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the configuration version." + } + ], + "responses": { + "200": { + "description": "Configuration version restored" + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/configuration-versions/{configuration_version_id}/actions/permanently_delete_backing_data": { + "x-vis": [ + "tfe" + ], + "post": { + "operationId": "permanentlyDeleteConfigurationVersion", + "summary": "Permanently Delete Configuration Version", + "description": "Permanently delete the backing files for a configuration version.\n\nThis operation is only available in Terraform Enterprise.", + "tags": [ + "configuration-versions" + ], + "parameters": [ + { + "in": "path", + "name": "configuration_version_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the configuration version." + } + ], + "responses": { + "200": { + "description": "Configuration version permanently deleted" + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/configuration-versions/{configuration_version_id}/download": { + "get": { + "operationId": "downloadConfigurationVersion", + "summary": "Download Configuration Version", + "description": "Generate a temporary URL to download the configuration version files.", + "tags": [ + "configuration-versions" + ], + "parameters": [ + { + "in": "path", + "name": "configuration_version_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the configuration version." + } + ], + "responses": { + "200": { + "description": ".tar.gz file containing the configuration version.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/organizations/{organization_name}/vcs-events": { + "get": { + "operationId": "listOrganizationVcsEvents", + "summary": "List VCS Events", + "description": "List VCS events for an organization.", + "tags": [ + "vcs-events" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the organization to list VCS events from." + }, + { + "in": "query", + "name": "filter[from]", + "schema": { + "type": "string", + "format": "date-time" + }, + "required": false, + "description": "RFC3339 formatted UTC timestamp. If omitted, defaults to 10 days ago." + }, + { + "in": "query", + "name": "filter[to]", + "schema": { + "type": "string", + "format": "date-time" + }, + "required": false, + "description": "RFC3339 formatted UTC timestamp. If omitted, defaults to now." + }, + { + "in": "query", + "name": "filter[oauth_client_external_ids]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Comma-separated list of OAuth client external IDs to filter by." + }, + { + "in": "query", + "name": "filter[levels]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Comma-separated list of event levels to filter by. Accepted values are \"info\" and \"error\"." + }, + { + "in": "query", + "name": "include", + "schema": { + "type": "string" + }, + "required": false, + "description": "Allows including related resource data. Only \"oauth_client\" is supported." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of VCS events", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/vcs-events" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/organizations/{organization_name}/vcs/tree": { + "get": { + "operationId": "getVcsTree", + "summary": "List directories in a repository", + "description": "This endpoint returns a list of directories in a repository \nat the root or at a specific reference (branch, tag, or commit SHA).\nNote: This endpoint only returns directories, not files.\n", + "tags": [ + "vcs" + ], + "parameters": [ + { + "name": "organization_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The name of the organization" + }, + { + "name": "oauth_token_id", + "in": "query", + "required": true, + "schema": { + "type": "string" + }, + "description": "The OAuth token ID to authenticate with the VCS provider" + }, + { + "name": "identifier", + "in": "query", + "required": true, + "schema": { + "type": "string" + }, + "description": "The repository identifier (e.g., \"owner/repo\")" + }, + { + "name": "branch", + "in": "query", + "required": false, + "schema": { + "type": "string" + }, + "description": "The branch, tag, or commit SHA to list directories for. \nIf not provided, the default branch will be used.\n" + }, + { + "name": "githubAppInstallationId", + "in": "query", + "required": false, + "schema": { + "type": "string" + }, + "description": "The GitHub App installation ID (only needed when using GitHub App authentication)" + } + ], + "responses": { + "200": { + "description": "Successfully retrieved repository directories", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the directory" + }, + "type": { + "type": "string", + "enum": [ + "vcs-tree" + ] + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Repository not found or user doesn't have access" + }, + "422": { + "description": "VCS provider error", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/organizations/{organization_name}/vcs/repo": { + "get": { + "operationId": "checkVcsRepository", + "summary": "Check if a repository exists", + "description": "This endpoint checks if a repository exists and is accessible to the user.\n", + "tags": [ + "vcs" + ], + "parameters": [ + { + "name": "organization_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The name of the organization" + }, + { + "name": "oauth_token_id", + "in": "query", + "required": true, + "schema": { + "type": "string" + }, + "description": "The OAuth token ID to authenticate with the VCS provider" + }, + { + "name": "identifier", + "in": "query", + "required": true, + "schema": { + "type": "string" + }, + "description": "The repository identifier (e.g., \"owner/repo\")" + } + ], + "responses": { + "200": { + "description": "Successfully checked repository existence", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/vcs-repo-check-envelope" + } + } + } + }, + "404": { + "description": "OAuth token not found or user doesn't have access" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/organizations/{organization_name}/registry-modules/validation": { + "get": { + "operationId": "validateRegistryModuleNames", + "summary": "Check if a module name and provider combination is available", + "description": "This endpoint checks if a module name and provider combination is available for use within an organization.\nIt returns a validation result indicating whether the name is already in use.\n", + "tags": [ + "registry" + ], + "parameters": [ + { + "name": "organization_name", + "in": "path", + "required": true, + "schema": { + "type": "string" + }, + "description": "The name of the organization" + }, + { + "name": "name", + "in": "query", + "required": true, + "schema": { + "type": "string" + }, + "description": "The name of the module to validate" + }, + { + "name": "provider", + "in": "query", + "required": true, + "schema": { + "type": "string" + }, + "description": "The provider of the module to validate" + } + ], + "responses": { + "200": { + "description": "Successfully validated the module name and provider", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/registry-module-address-validations-envelope" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "404": { + "description": "Organization not found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Validation error", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/organizations/{organization_name}/registry-modules/{registry_name}/{namespace}/{name}/{provider}": { + "get": { + "operationId": "getRegistryModule", + "summary": "Show a registry module", + "description": "Returns details for a registry module, including its status, publishing\nmechanism, version statuses, and VCS settings when available to the\nrequesting organization.\n", + "tags": [ + "registry" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the organization requesting the module." + }, + { + "in": "path", + "name": "registry_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The registry the module belongs to (e.g. \"private\" or \"public\")." + }, + { + "in": "path", + "name": "namespace", + "schema": { + "type": "string" + }, + "required": true, + "description": "The namespace of the module." + }, + { + "in": "path", + "name": "name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the module." + }, + { + "in": "path", + "name": "provider", + "schema": { + "type": "string" + }, + "required": true, + "description": "The provider of the module." + } + ], + "responses": { + "200": { + "description": "The registry module was found.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/registry-modules-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "patch": { + "operationId": "updateRegistryModule", + "summary": "Update a registry module", + "description": "When updating a VCS-backed private registry module, you can change the publishing\nmechanism (branch, tags, or tag prefix) and the VCS connection itself.\nChanging the connection re-validates the new VCS source and re-ingests the\nmodule.\n", + "tags": [ + "registry" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the organization that owns the module." + }, + { + "in": "path", + "name": "registry_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The registry the module belongs to (e.g. \"private\")." + }, + { + "in": "path", + "name": "namespace", + "schema": { + "type": "string" + }, + "required": true, + "description": "The namespace of the module." + }, + { + "in": "path", + "name": "name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the module." + }, + { + "in": "path", + "name": "provider", + "schema": { + "type": "string" + }, + "required": true, + "description": "The provider of the module." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/registry-modules-envelope" + } + } + } + }, + "responses": { + "200": { + "description": "The registry module was updated.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/registry-modules-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/organizations/{organization_name}/tests/registry-modules/{registry_name}/{namespace}/{name}/{provider}/test-runs/{test_run_id}/cleanups/{id}": { + "get": { + "operationId": "getTestRunCleanup", + "summary": "Get a Test Run Cleanup", + "description": "Get details about a specific cleanup attempt associated with a test run.\n", + "tags": [ + "registry" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "required": true, + "schema": { + "type": "string" + }, + "description": "The name of the organization." + }, + { + "in": "path", + "name": "registry_name", + "required": true, + "schema": { + "type": "string" + }, + "description": "The registry host name." + }, + { + "in": "path", + "name": "namespace", + "required": true, + "schema": { + "type": "string" + }, + "description": "The namespace of the registry module." + }, + { + "in": "path", + "name": "name", + "required": true, + "schema": { + "type": "string" + }, + "description": "The name of the registry module." + }, + { + "in": "path", + "name": "provider", + "required": true, + "schema": { + "type": "string" + }, + "description": "The provider of the registry module." + }, + { + "in": "path", + "name": "test_run_id", + "required": true, + "schema": { + "type": "string" + }, + "description": "The ID of the test run." + }, + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string" + }, + "description": "The ID of the test run cleanup." + } + ], + "responses": { + "200": { + "description": "Test run cleanup details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/test-run-cleanups-envelope" + } + } + } + }, + "404": { + "description": "Test run cleanup not found or user unauthorized to perform action", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/organizations/{organization_name}/ssh-keys": { + "get": { + "operationId": "listSshKeys", + "tags": [ + "ssh-keys" + ], + "summary": "List SSH Keys", + "description": "List all SSH keys for an organization.", + "parameters": [ + { + "name": "organization_name", + "in": "path", + "required": true, + "description": "The name of the organization.", + "schema": { + "type": "string", + "example": "my-organization" + } + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ssh-keys" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + } + } + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "post": { + "operationId": "createSshKey", + "tags": [ + "ssh-keys" + ], + "summary": "Create an SSH Key", + "description": "Create a new SSH key for an organization.", + "parameters": [ + { + "name": "organization_name", + "in": "path", + "required": true, + "description": "The name of the organization.", + "schema": { + "type": "string", + "example": "my-organization" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/ssh-keys-envelope" + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/ssh-keys-envelope" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/ssh-keys/{ssh_key_id}": { + "get": { + "operationId": "getSshKey", + "tags": [ + "ssh-keys" + ], + "summary": "Get an SSH Key", + "description": "Retrieve the details of a single SSH key.", + "parameters": [ + { + "name": "ssh_key_id", + "in": "path", + "required": true, + "description": "The ID of the SSH key.", + "schema": { + "type": "string", + "example": "sshkey-xxxxxxxxxxxxxxxx" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/ssh-keys-envelope" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "patch": { + "operationId": "updateSshKey", + "tags": [ + "ssh-keys" + ], + "summary": "Update an SSH Key", + "description": "Update the name of an SSH key.", + "parameters": [ + { + "name": "ssh_key_id", + "in": "path", + "required": true, + "description": "The ID of the SSH key.", + "schema": { + "type": "string", + "example": "sshkey-xxxxxxxxxxxxxxxx" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/ssh-keys-envelope" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/ssh-keys-envelope" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "delete": { + "operationId": "deleteSshKey", + "tags": [ + "ssh-keys" + ], + "summary": "Delete an SSH Key", + "description": "Delete an SSH key.", + "parameters": [ + { + "name": "ssh_key_id", + "in": "path", + "required": true, + "description": "The ID of the SSH key.", + "schema": { + "type": "string", + "example": "sshkey-xxxxxxxxxxxxxxxx" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "404": { + "description": "Not Found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/workspaces/{workspace_id}/change-requests": { + "get": { + "operationId": "listWorkspaceChangeRequests", + "summary": "List Change Requests in a Workspace", + "description": "List all change requests for a workspace.", + "tags": [ + "change-requests" + ], + "parameters": [ + { + "in": "path", + "name": "workspace_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The workspace ID." + }, + { + "in": "query", + "name": "archive", + "schema": { + "type": "boolean" + }, + "required": false, + "description": "When true, returns only archived change requests. When false, returns only unarchived change requests. When omitted, returns all change requests ordered by creation date." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of change requests", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/workspace-change-requests" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/change-requests/{change_request_id}": { + "get": { + "operationId": "showChangeRequest", + "summary": "Show a Change Request", + "description": "Get details about a specific change request.", + "tags": [ + "change-requests" + ], + "parameters": [ + { + "in": "path", + "name": "change_request_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The change request ID." + } + ], + "responses": { + "200": { + "description": "Change request details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspace-change-requests-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/change-requests/{change_request_id}/actions/archive": { + "get": { + "operationId": "getChangeRequestArchive", + "summary": "Get Change Request Archive Status", + "description": "Get the current state of a change request, including its archive status.", + "tags": [ + "change-requests" + ], + "parameters": [ + { + "in": "path", + "name": "change_request_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The change request ID." + } + ], + "responses": { + "200": { + "description": "Change request details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspace-change-requests-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "post": { + "operationId": "archiveChangeRequest", + "summary": "Archive a Change Request", + "description": "Archive a change request to mark it as completed.", + "tags": [ + "change-requests" + ], + "parameters": [ + { + "in": "path", + "name": "change_request_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The change request ID." + } + ], + "responses": { + "200": { + "description": "Change request successfully archived", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspace-change-requests-envelope" + } + } + } + }, + "400": { + "description": "The change request is already archived.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/oauth-clients/{oauth_client_id}": { + "get": { + "operationId": "getOAuthClient", + "summary": "Get an OAuth Client", + "description": "Show details of an existing OAuth client.", + "tags": [ + "oauth-clients" + ], + "parameters": [ + { + "in": "path", + "name": "oauth_client_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the OAuth Client." + }, + { + "in": "query", + "name": "show_affected_workspaces", + "schema": { + "type": "boolean" + }, + "required": false, + "description": "If true, includes names of up to 25 affected workspaces and the total count." + } + ], + "responses": { + "200": { + "description": "OAuth Client details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/oauth-clients-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "patch": { + "operationId": "updateOAuthClient", + "summary": "Update an OAuth Client", + "description": "Update settings of an existing OAuth client.", + "tags": [ + "oauth-clients" + ], + "parameters": [ + { + "in": "path", + "name": "oauth_client_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the OAuth Client to update." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/oauth-clients-envelope" + } + } + } + }, + "responses": { + "200": { + "description": "OAuth Client updated", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/oauth-clients-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "delete": { + "operationId": "destroyOAuthClient", + "summary": "Destroy an OAuth Client", + "description": "Remove an existing OAuth client and unlink any associated workspaces.", + "tags": [ + "oauth-clients" + ], + "parameters": [ + { + "in": "path", + "name": "oauth_client_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the OAuth Client to destroy." + } + ], + "responses": { + "204": { + "description": "OAuth Client successfully destroyed." + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/oauth-clients": { + "post": { + "operationId": "createOAuthClient", + "summary": "Create an OAuth Client", + "description": "Create a VCS connection between an organization and a VCS provider. The organization is specified via the `organization-id` attribute. This endpoint allows you to provide a pre-generated OAuth token string instead of going through the OAuth Application flow.\n", + "tags": [ + "oauth-clients" + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/oauth-clients-envelope" + } + } + } + }, + "responses": { + "201": { + "description": "OAuth Client created", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/oauth-clients-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/organizations/{organization_name}/oauth-clients": { + "get": { + "operationId": "listOAuthClients", + "summary": "List OAuth Clients", + "description": "List all VCS connections between an organization and its VCS providers.", + "tags": [ + "oauth-clients" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the organization." + }, + { + "in": "query", + "name": "show_affected_workspaces", + "schema": { + "type": "boolean" + }, + "required": false, + "description": "If true, includes names of up to 25 affected workspaces and total count per client." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of OAuth Clients", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/oauth-clients" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "post": { + "operationId": "createOAuthClientForOrganization", + "summary": "Create an OAuth Client for an Organization", + "description": "Create a VCS connection between an organization and a VCS provider. This endpoint allows you to provide a pre-generated OAuth token string instead of going through the OAuth Application flow.\n", + "tags": [ + "oauth-clients" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the organization." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/oauth-clients-envelope" + } + } + } + }, + "responses": { + "201": { + "description": "OAuth Client created", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/oauth-clients-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/oauth-clients/{oauth_client_id}/relationships/projects": { + "post": { + "operationId": "attachOAuthClientToProjects", + "summary": "Attach an OAuth Client to Projects", + "description": "Attach an OAuth client to one or more projects.", + "tags": [ + "oauth-clients" + ], + "parameters": [ + { + "in": "path", + "name": "oauth_client_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the OAuth Client to attach to projects." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/projects-identifier-array-document" + } + } + } + }, + "responses": { + "204": { + "description": "OAuth Client successfully attached to projects." + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "delete": { + "operationId": "detachOAuthClientFromProjects", + "summary": "Detach an OAuth Client from Projects", + "description": "Detach an OAuth client from one or more projects.", + "tags": [ + "oauth-clients" + ], + "parameters": [ + { + "in": "path", + "name": "oauth_client_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the OAuth Client to detach from projects." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/projects-identifier-array-document" + } + } + } + }, + "responses": { + "204": { + "description": "OAuth Client successfully detached from projects." + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/oauth-tokens/{oauth_token_id}": { + "get": { + "tags": [ + "oauth-tokens" + ], + "summary": "Show an OAuth Token", + "description": "Get details about an OAuth token.", + "operationId": "getOauthToken", + "parameters": [ + { + "name": "oauth_token_id", + "in": "path", + "required": true, + "description": "The ID of the OAuth token.", + "schema": { + "type": "string", + "example": "ot-xxxxxxxxxxxxxxxx" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/oauth-tokens-envelope" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "patch": { + "tags": [ + "oauth-tokens" + ], + "summary": "Update an OAuth Token", + "description": "Update an OAuth token by setting its SSH key.", + "operationId": "updateOauthToken", + "parameters": [ + { + "name": "oauth_token_id", + "in": "path", + "required": true, + "description": "The ID of the OAuth token.", + "schema": { + "type": "string", + "example": "ot-xxxxxxxxxxxxxxxx" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/oauth-tokens-envelope" + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/oauth-tokens-envelope" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Unprocessable Content", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "delete": { + "tags": [ + "oauth-tokens" + ], + "summary": "Destroy an OAuth Token", + "description": "Destroy an OAuth token.", + "operationId": "deleteOauthToken", + "parameters": [ + { + "name": "oauth_token_id", + "in": "path", + "required": true, + "description": "The ID of the OAuth token.", + "schema": { + "type": "string", + "example": "ot-xxxxxxxxxxxxxxxx" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "404": { + "description": "Not Found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/organizations/{organization_name}/oauth-tokens": { + "get": { + "tags": [ + "oauth-tokens" + ], + "summary": "List OAuth Tokens for an Organization", + "description": "List all OAuth tokens for a given organization.", + "operationId": "listOauthTokensForOrganization", + "parameters": [ + { + "name": "organization_name", + "in": "path", + "required": true, + "description": "The name of the organization.", + "schema": { + "type": "string", + "example": "my-organization" + } + }, + { + "name": "filter[provider]", + "in": "query", + "required": false, + "description": "Filter tokens by VCS provider name.", + "schema": { + "type": "string", + "example": "github" + } + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/oauth-tokens" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + } + } + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/oauth-clients/{oauth_client_id}/oauth-tokens": { + "get": { + "tags": [ + "oauth-tokens" + ], + "summary": "List OAuth Tokens for an OAuth Client", + "description": "List all OAuth tokens for a given OAuth client.", + "operationId": "listOauthTokensForOauthClient", + "parameters": [ + { + "name": "oauth_client_id", + "in": "path", + "required": true, + "description": "The ID of the OAuth client.", + "schema": { + "type": "string", + "example": "oc-xxxxxxxxxxxxxxxx" + } + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/oauth-tokens" + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + } + } + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/oauth-tokens/{oauth_token_id}/authorized-repos": { + "get": { + "tags": [ + "oauth-tokens" + ], + "summary": "List Authorized Repositories for an OAuth Token", + "description": "List all repositories that the OAuth token is authorized to access.", + "operationId": "listAuthorizedReposForOauthToken", + "parameters": [ + { + "name": "oauth_token_id", + "in": "path", + "required": true, + "description": "The ID of the OAuth token.", + "schema": { + "type": "string", + "example": "ot-xxxxxxxxxxxxxxxx" + } + }, + { + "name": "organization", + "in": "query", + "required": false, + "description": "The VCS organization name to scope repositories to. Required for Azure DevOps providers.", + "schema": { + "type": "string" + } + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/authorized-repos" + } + }, + "meta": { + "type": "object", + "properties": { + "next-page": { + "type": "integer", + "nullable": true, + "description": "The next page number, if more pages are available." + } + } + } + } + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/oauth-tokens/{oauth_token_id}/vcs-organizations": { + "get": { + "tags": [ + "oauth-tokens" + ], + "summary": "List VCS Organizations for an OAuth Token", + "description": "List all VCS organizations accessible via the OAuth token. Only applicable to Azure DevOps providers.", + "operationId": "listVcsOrganizationsForOauthToken", + "parameters": [ + { + "name": "oauth_token_id", + "in": "path", + "required": true, + "description": "The ID of the OAuth token.", + "schema": { + "type": "string", + "example": "ot-xxxxxxxxxxxxxxxx" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/vcs-organization" + } + } + } + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/github-app-installations": { + "get": { + "operationId": "listGithubAppInstallations", + "summary": "List GitHub App Installations", + "description": "List GitHub App installations available to the current user.", + "tags": [ + "github-app-installations" + ], + "parameters": [ + { + "in": "query", + "name": "filter[name]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Filter by GitHub organization or login name." + }, + { + "in": "query", + "name": "filter[installation_id]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Filter by GitHub installation ID." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of GitHub App installations", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/github-app-installations" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/github-app-installations/{github_app_installation_id}/repos": { + "get": { + "operationId": "listGithubAppInstallationRepos", + "summary": "List GitHub App Installation Repositories", + "description": "List repositories accessible through a GitHub App installation.", + "tags": [ + "github-app-installations" + ], + "parameters": [ + { + "in": "path", + "name": "github_app_installation_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the GitHub App installation." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of repositories", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/github-app-repos" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/github-app/installation/{github_app_installation_id}": { + "get": { + "operationId": "getGithubAppInstallation", + "summary": "Show GitHub App Installation", + "description": "Get details about a GitHub App installation.", + "tags": [ + "github-app-installations" + ], + "parameters": [ + { + "in": "path", + "name": "github_app_installation_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the GitHub App installation." + } + ], + "responses": { + "200": { + "description": "GitHub App installation details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/github-app-installations-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/github-app/installations": { + "get": { + "operationId": "listGithubAppInstallationsForCurrentUser", + "summary": "List GitHub App Installations for Current User", + "description": "List GitHub App installations accessible to the current authenticated user.", + "tags": [ + "github-app-installations" + ], + "parameters": [ + { + "in": "query", + "name": "filter[name]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Filter by GitHub organization or login name." + }, + { + "in": "query", + "name": "filter[installation_id]", + "schema": { + "type": "string" + }, + "required": false, + "description": "Filter by GitHub installation ID." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of GitHub App installations", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/github-app-installations" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/organizations/{organization_name}/github-app-installations": { + "get": { + "operationId": "listOrganizationGithubAppInstallations", + "summary": "List Organization GitHub App Installations", + "description": "List GitHub App installations linked to an organization.", + "tags": [ + "github-app-installations" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the organization." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of GitHub App installations", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/github-app-installations" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/organizations/{organization_name}/github-app-installations/{github_app_installation_id}/repos": { + "get": { + "operationId": "listOrganizationGithubAppInstallationRepos", + "summary": "List Organization GitHub App Installation Repositories", + "description": "List repositories accessible through a GitHub App installation linked to an organization.", + "tags": [ + "github-app-installations" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the organization." + }, + { + "in": "path", + "name": "github_app_installation_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the GitHub App installation." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of repositories", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/github-app-repos" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/organizations/{organization_name}/github-app-installations/{github_app_installation_id}/link-account": { + "post": { + "operationId": "linkOrganizationGithubAppInstallation", + "summary": "Link GitHub App Installation to Organization", + "description": "Link a GitHub App installation to an organization.", + "tags": [ + "github-app-installations" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the organization." + }, + { + "in": "path", + "name": "github_app_installation_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the GitHub App installation." + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "default": { + "description": "Error details", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + } + }, + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/tasks/{id}": { + "get": { + "operationId": "getTask", + "summary": "Get a Run Task", + "description": "Get details about a run task.", + "tags": [ + "run-tasks" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the run task." + }, + { + "in": "query", + "name": "include", + "schema": { + "type": "string" + }, + "required": false, + "description": "Allows including related resource data. Value must be a comma-separated list containing one or more of `workspace_tasks` or `workspace_tasks.workspace`.\n" + } + ], + "responses": { + "200": { + "description": "Run task details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/tasks-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "patch": { + "operationId": "updateTask", + "summary": "Update a Run Task", + "description": "Update a run task.", + "tags": [ + "run-tasks" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the run task." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/tasks-envelope" + } + } + } + }, + "responses": { + "200": { + "description": "Run task updated", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/tasks-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "delete": { + "operationId": "deleteTask", + "summary": "Delete a Run Task", + "description": "Delete a run task.", + "tags": [ + "run-tasks" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the run task." + } + ], + "responses": { + "204": { + "description": "Run task deleted" + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/organizations/{organization_name}/tasks": { + "get": { + "operationId": "listOrganizationTasks", + "summary": "List Run Tasks", + "description": "List all run tasks in an organization.", + "tags": [ + "run-tasks" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the organization." + }, + { + "in": "query", + "name": "include", + "schema": { + "type": "string" + }, + "required": false, + "description": "Allows including related resource data. Value must be a comma-separated list containing one or more of `workspace_tasks` or `workspace_tasks.workspace`.\n" + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of run tasks", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/tasks" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "post": { + "operationId": "createTask", + "summary": "Create a Run Task", + "description": "Create a run task in an organization.", + "tags": [ + "run-tasks" + ], + "parameters": [ + { + "in": "path", + "name": "organization_name", + "schema": { + "type": "string" + }, + "required": true, + "description": "The name of the organization." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/tasks-envelope" + } + } + } + }, + "responses": { + "201": { + "description": "Run task created", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/tasks-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/tasks/{id}/relationships/workspace-tasks": { + "get": { + "operationId": "listTaskWorkspaceTasks", + "summary": "List Workspace Run Tasks for a Run Task", + "description": "List all workspace run tasks associated with a run task.", + "tags": [ + "run-tasks" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the run task." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of workspace run tasks", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/workspace-tasks" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/workspaces/{workspace_id}/tasks": { + "get": { + "operationId": "listWorkspaceTasks", + "summary": "List Workspace Run Tasks", + "description": "List all run tasks associated with a workspace.", + "tags": [ + "run-tasks" + ], + "parameters": [ + { + "in": "path", + "name": "workspace_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the workspace." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of workspace run tasks", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/workspace-tasks" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "post": { + "operationId": "createWorkspaceTask", + "summary": "Associate a Run Task to a Workspace", + "description": "Associate an existing run task to a workspace.", + "tags": [ + "run-tasks" + ], + "parameters": [ + { + "in": "path", + "name": "workspace_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the workspace." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspace-tasks-envelope" + } + } + } + }, + "responses": { + "201": { + "description": "Workspace run task created", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspace-tasks-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/workspaces/{workspace_id}/tasks/{id}": { + "get": { + "operationId": "getWorkspaceTask", + "summary": "Show a Workspace Run Task", + "description": "Get details about a workspace run task.", + "tags": [ + "run-tasks" + ], + "parameters": [ + { + "in": "path", + "name": "workspace_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the workspace." + }, + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the workspace run task." + } + ], + "responses": { + "200": { + "description": "Workspace run task details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspace-tasks-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "patch": { + "operationId": "updateWorkspaceTask", + "summary": "Update a Workspace Run Task", + "description": "Update a workspace run task.", + "tags": [ + "run-tasks" + ], + "parameters": [ + { + "in": "path", + "name": "workspace_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the workspace." + }, + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the workspace run task." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspace-tasks-envelope" + } + } + } + }, + "responses": { + "200": { + "description": "Workspace run task updated", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspace-tasks-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "delete": { + "operationId": "deleteWorkspaceTask", + "summary": "Delete a Workspace Run Task", + "description": "Delete a workspace run task, dissociating the run task from the workspace.", + "tags": [ + "run-tasks" + ], + "parameters": [ + { + "in": "path", + "name": "workspace_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the workspace." + }, + { + "in": "path", + "name": "id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the workspace run task." + } + ], + "responses": { + "204": { + "description": "Workspace run task deleted" + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/task-stages/{task_stage_id}": { + "get": { + "operationId": "getTaskStage", + "summary": "Show a Run Task Stage", + "description": "Get details about a specific run task stage.", + "tags": [ + "task-stages" + ], + "parameters": [ + { + "in": "path", + "name": "task_stage_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the task stage to show." + }, + { + "in": "query", + "name": "include", + "schema": { + "type": "string" + }, + "required": false, + "description": "A comma-separated list of related resources to include. Supported values: run, run.workspace, task-results, policy-evaluations." + } + ], + "responses": { + "200": { + "description": "Task stage details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/task-stages-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/task-stages/{task_stage_id}/actions/override": { + "post": { + "operationId": "overrideTaskStage", + "summary": "Override a Task Stage", + "description": "Override a task stage that is in the awaiting_override status, allowing the run to continue even when run tasks have failed.", + "tags": [ + "task-stages" + ], + "parameters": [ + { + "in": "path", + "name": "task_stage_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the task stage to override." + } + ], + "responses": { + "200": { + "description": "Task stage successfully overridden", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/task-stages-envelope" + } + } + } + }, + "409": { + "description": "The task stage is not in an overridable state or has no overridable failures.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/runs/{run_id}/task-stages": { + "get": { + "operationId": "listRunTaskStages", + "summary": "List the Run Task Stages in a Run", + "description": "List the run task stages associated with a run.", + "tags": [ + "task-stages" + ], + "parameters": [ + { + "in": "path", + "name": "run_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the run to list task stages for." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of run task stages", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/task-stages" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/task-results/{task_result_id}": { + "get": { + "operationId": "getTaskResult", + "summary": "Show a Run Task Result", + "description": "Get details about a specific run task result.", + "tags": [ + "task-stages" + ], + "parameters": [ + { + "in": "path", + "name": "task_result_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the task result to show." + } + ], + "responses": { + "200": { + "description": "Task result details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/task-results-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/task-results/{task_result_id}/body": { + "get": { + "operationId": "getTaskResultBody", + "summary": "Download Task Result Body", + "description": "Download the body content of a native task result. This endpoint redirects to a \npre-signed URL for downloading the task result data stored in object storage.\n", + "tags": [ + "task-stages" + ], + "parameters": [ + { + "in": "path", + "name": "task_result_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the task result." + } + ], + "responses": { + "200": { + "description": "File containing the task result body.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Task result not found or has no body content", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/task-results/{task_result_id}/callback": { + "patch": { + "operationId": "callbackTaskResult", + "summary": "Update a Run Task Result", + "description": "Update a run task result with status, message, and optional outcome data. This endpoint is used by run task integrations to report execution results back to HCP Terraform. Requires a url_code query parameter for authentication.", + "tags": [ + "task-stages" + ], + "parameters": [ + { + "in": "path", + "name": "task_result_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the task result to update." + }, + { + "in": "query", + "name": "url_code", + "schema": { + "type": "string" + }, + "required": false, + "description": "The callback authentication token issued to the run task integration. Required for run task integrations; not required for token-authenticated requests." + } + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/task-results-envelope" + } + } + } + }, + "responses": { + "200": { + "description": "Task result updated successfully", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/task-results-envelope" + } + } + } + }, + "409": { + "description": "The task result is in a terminal state and cannot be updated.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "422": { + "description": "Invalid attributes provided.", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/task-results/{task_result_id}/outcomes": { + "get": { + "operationId": "listTaskResultOutcomes", + "summary": "List the Outcomes for a Run Task Result", + "description": "List the run task result outcomes associated with a run task result.", + "tags": [ + "task-stages" + ], + "parameters": [ + { + "in": "path", + "name": "task_result_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the task result to list outcomes for." + }, + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of run task result outcomes", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/task-result-outcomes" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/task-result-outcomes/{task_result_outcome_id}": { + "get": { + "operationId": "getTaskResultOutcome", + "summary": "Show a Run Task Result Outcome", + "description": "Get details about a specific run task result outcome.", + "tags": [ + "task-stages" + ], + "parameters": [ + { + "in": "path", + "name": "task_result_outcome_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "The ID of the task result outcome to show." + } + ], + "responses": { + "200": { + "description": "Task result outcome details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/task-result-outcomes-envelope" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/workspace-transfers": { + "get": { + "operationId": "listWorkspaceTransfers", + "summary": "List Workspace Transfers", + "description": "List all workspace transfers you have access to.", + "tags": [ + "workspace-transfers" + ], + "parameters": [ + { + "$ref": "#/components/parameters/page_number" + }, + { + "$ref": "#/components/parameters/page_size" + } + ], + "responses": { + "200": { + "description": "List of workspace transfers", + "content": { + "application/vnd.api+json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/workspace-transfers" + } + }, + "meta": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + } + } + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + }, + "post": { + "operationId": "createWorkspaceTransfer", + "summary": "Create a Workspace Transfer", + "description": "Queue a new workspace transfer across organizations.", + "tags": [ + "workspace-transfers" + ], + "requestBody": { + "required": true, + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspace-transfers-envelope" + } + } + } + }, + "responses": { + "201": { + "description": "Workspace transfer created", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspace-transfers-envelope" + } + } + } + }, + "422": { + "description": "Validation error", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/workspace-transfers/{workspace_transfer_id}": { + "get": { + "operationId": "getWorkspaceTransfer", + "summary": "Get Workspace Transfer details", + "description": "Get details about a workspace transfer.", + "tags": [ + "workspace-transfers" + ], + "parameters": [ + { + "in": "path", + "name": "workspace_transfer_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "Workspace Transfer ID" + }, + { + "in": "query", + "name": "include", + "schema": { + "type": "string" + }, + "required": false, + "description": "Related resources to include (e.g., operations)" + } + ], + "responses": { + "200": { + "description": "Workspace transfer details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspace-transfers-envelope" + } + } + } + }, + "404": { + "description": "Workspace transfer not found", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/workspace-transfers/{workspace_transfer_id}/actions/resume": { + "post": { + "operationId": "resumeWorkspaceTransfer", + "summary": "Resume a Workspace Transfer", + "description": "Resume a paused workspace transfer. A transfer pauses automatically:\n- After data migration completes, awaiting approval before source workspace deletion (`awaiting_approval`)\n- If source workspace deletion times out (`source_workspace_deletion_stuck`)\nOnce resumed, the transfer proceeds with the remaining operations.\n", + "tags": [ + "workspace-transfers" + ], + "parameters": [ + { + "in": "path", + "name": "workspace_transfer_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "Workspace Transfer ID" + } + ], + "responses": { + "200": { + "description": "Workspace transfer resumed", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspace-transfers-envelope" + } + } + } + }, + "409": { + "description": "Transfer is not paused", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + }, + "/workspace-transfers/{workspace_transfer_id}/actions/cancel": { + "post": { + "operationId": "cancelWorkspaceTransfer", + "summary": "Cancel a Workspace Transfer", + "description": "Cancel a workspace transfer before the source workspace deletion begins.\nOnce the `remove_source_workspace` operation starts, the transfer cannot be canceled.\nCanceling leaves the source workspace intact but locked. You cannot resume a canceled transfer.\n", + "tags": [ + "workspace-transfers" + ], + "parameters": [ + { + "in": "path", + "name": "workspace_transfer_id", + "schema": { + "type": "string" + }, + "required": true, + "description": "Workspace Transfer ID" + } + ], + "responses": { + "200": { + "description": "Workspace transfer canceled", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/workspace-transfers-envelope" + } + } + } + }, + "409": { + "description": "Transfer cannot be canceled (already started source workspace deletion, completed, or already canceled)", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + }, + "default": { + "description": "Error details", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/errors" + } + } + } + } + } + } + } + }, + "components": { + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer" + } + }, + "schemas": { + "errors": { + "type": "object", + "properties": { + "errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "title": { + "type": "string" + }, + "detail": { + "type": "string" + } + } + } + } + } + }, + "related": { + "type": "object", + "properties": { + "related": { + "type": "string" + } + } + }, + "links_related": { + "type": "object", + "properties": { + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "self": { + "type": "object", + "properties": { + "self": { + "type": "string" + } + } + }, + "users": { + "type": "object", + "required": [ + "id", + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "users" + ] + }, + "attributes": { + "type": "object", + "properties": { + "username": { + "type": "string", + "nullable": true + }, + "is-service-account": { + "description": "Indicates whether this user is a synthetic user representing a team or organization.", + "type": "boolean" + }, + "avatar-url": { + "type": "string", + "nullable": true + }, + "auth-method": { + "type": "string" + }, + "v2-only": { + "type": "boolean" + }, + "is-admin": { + "type": "boolean" + }, + "is-site-admin": { + "description": "Deprecated. Use is-admin.", + "type": "boolean" + }, + "is-sso-login": { + "type": "boolean" + }, + "is-confirmed": { + "type": "boolean" + }, + "is-unified": { + "type": "boolean" + }, + "is-sudo": { + "type": "boolean" + }, + "email": { + "type": "string" + }, + "unconfirmed-email": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "enterprise-support": { + "type": "boolean" + }, + "has-linked-hcp": { + "type": "boolean" + }, + "has-git-hub-app-token": { + "type": "boolean" + }, + "two-factor": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "verified": { + "type": "boolean" + } + } + }, + "permissions": { + "type": "object", + "properties": { + "can-create-organization": { + "type": "boolean" + }, + "can-view-organizations": { + "type": "boolean" + }, + "can-view-settings": { + "type": "boolean" + }, + "can-view-smtp-settings": { + "type": "boolean" + }, + "can-view-twilio-settings": { + "type": "boolean" + }, + "can-view-saml-settings": { + "type": "boolean" + }, + "can-view-admin-workspaces": { + "type": "boolean" + }, + "can-view-admin-runs": { + "type": "boolean" + }, + "can-view-customization-settings": { + "type": "boolean" + }, + "can-view-cost-estimation-settings": { + "type": "boolean" + }, + "can-view-tool-versions": { + "type": "boolean" + }, + "can-create-tool-versions": { + "type": "boolean" + }, + "can-view-general-settings": { + "type": "boolean" + }, + "can-use-sql-runner": { + "type": "boolean" + }, + "can-view-profile": { + "type": "boolean" + }, + "can-change-email": { + "type": "boolean" + }, + "can-change-username": { + "type": "boolean" + }, + "can-change-password": { + "type": "boolean" + }, + "can-manage-sessions": { + "type": "boolean" + }, + "can-manage-user-tokens": { + "type": "boolean" + }, + "can-update-user": { + "type": "boolean" + }, + "can-reenable-2fa-by-unlinking": { + "type": "boolean", + "x-vis": [ + "hcpt" + ], + "description": "This attribute is only available in HCP Terraform." + }, + "can-manage-hcp-accounts": { + "type": "boolean", + "x-vis": [ + "hcpt" + ], + "description": "This attribute is only available in HCP Terraform." + } + } + } + } + }, + "relationships": { + "type": "object", + "properties": { + "authentication-tokens": { + "$ref": "#/components/schemas/links_related" + }, + "github-app-oauth-tokens": { + "$ref": "#/components/schemas/links_related" + }, + "authenticated-resource": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "organizations", + "runs", + "users", + "teams" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + } + } + }, + "links": { + "$ref": "#/components/schemas/self" + } + } + }, + "users-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/users" + } + } + }, + "hcp-billing-accounts-id": { + "type": "object", + "nullable": false, + "properties": { + "data": { + "type": "object", + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "hcp-billing-account" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "feature-sets-id": { + "type": "object", + "nullable": true, + "required": [ + "data" + ], + "properties": { + "data": { + "type": "object", + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "feature-sets" + ] + } + } + } + } + }, + "hcp-organization": { + "type": "object", + "required": [ + "id", + "type", + "attributes", + "relationships" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "attributes": { + "type": "object", + "required": [ + "name", + "is-hcp-admin" + ], + "properties": { + "name": { + "type": "string" + }, + "hcp-owner-email": { + "type": "string", + "nullable": true + }, + "is-hcp-admin": { + "type": "boolean" + } + } + }, + "relationships": { + "type": "object", + "required": [ + "default-account", + "connected-plans" + ], + "properties": { + "default-account": { + "$ref": "#/components/schemas/hcp-billing-accounts-id" + }, + "connected-plans": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/feature-sets-id" + } + } + } + } + } + } + } + }, + "hcp-organization-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/hcp-organization" + } + } + }, + "hcp-billing-account": { + "type": "object", + "required": [ + "id", + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "attributes": { + "type": "object", + "required": [ + "project-id", + "hcp-organization-name", + "hcp-organization-id", + "balance", + "card-brand", + "card-last4", + "card-exp-month", + "card-exp-year", + "account-type", + "status", + "payment-provider" + ], + "properties": { + "project-id": { + "type": "string" + }, + "hcp-organization-name": { + "type": "string" + }, + "hcp-organization-id": { + "type": "string" + }, + "balance": { + "type": "number" + }, + "card-brand": { + "type": "string", + "nullable": true + }, + "card-last4": { + "type": "string", + "nullable": true + }, + "card-exp-month": { + "type": "integer", + "nullable": true + }, + "card-exp-year": { + "type": "integer", + "nullable": true + }, + "account-type": { + "type": "string" + }, + "status": { + "type": "string" + }, + "payment-provider": { + "type": "string", + "nullable": true + }, + "is-payment-method-configured": { + "type": "boolean" + }, + "flex-version": { + "type": "string", + "nullable": true + } + } + } + } + }, + "feature-sets": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The ID of the feature set" + }, + "type": { + "type": "string", + "enum": [ + "feature-sets" + ] + }, + "attributes": { + "type": "object", + "properties": { + "assessments": { + "type": "boolean", + "description": "Whether the feature set includes assessments" + }, + "audit-logging": { + "type": "boolean", + "description": "Whether the feature set includes audit logging" + }, + "can-self-service-downgrade": { + "type": "boolean", + "description": "Whether the organization can self-service downgrade from this feature set" + }, + "change-requests": { + "type": "boolean", + "description": "Whether the feature set includes change requests" + }, + "cost": { + "type": "number", + "description": "The cost of the feature set in cents" + }, + "cost-estimation": { + "type": "boolean", + "description": "Whether the feature set includes cost estimation" + }, + "default-agents-ceiling": { + "type": "number", + "description": "Default maximum number of concurrent agents" + }, + "default-runs-ceiling": { + "type": "number", + "description": "Default maximum number of concurrent runs" + }, + "description": { + "type": "string", + "description": "Description of the feature set" + }, + "global-run-tasks": { + "type": "boolean", + "description": "Whether the feature set includes global run tasks" + }, + "hyok": { + "type": "boolean", + "description": "Whether the feature set includes Hold Your Own Key encryption" + }, + "identifier": { + "type": "string", + "description": "Unique identifier for the feature set" + }, + "terraform-actions": { + "type": "boolean", + "description": "Whether the feature set includes Terraform Actions features" + }, + "is-current": { + "type": "boolean", + "description": "Whether this is a current/active feature set" + }, + "is-free-tier": { + "type": "boolean", + "description": "Whether this is a free tier feature set" + }, + "is-managed-resource-plan": { + "type": "boolean", + "description": "Whether this is a managed resource plan" + }, + "module-deprecations": { + "type": "boolean", + "description": "Whether this feature set includes module deprecations" + }, + "module-revocations": { + "type": "boolean", + "description": "Whether this feature set includes module revocations" + }, + "module-tests-agent-support": { + "type": "boolean" + }, + "module-tests-generation": { + "type": "boolean", + "description": "Whether the feature set includes module test generation" + }, + "name": { + "type": "string", + "description": "Name of the feature set" + }, + "no-code-modules": { + "type": "boolean", + "description": "Whether the feature set includes no-code modules" + }, + "plan": { + "type": "string", + "nullable": true, + "description": "Associated plan ID" + }, + "policy-enforcement": { + "type": "boolean", + "description": "Whether the feature set includes policy enforcement" + }, + "policy-limit": { + "type": "number", + "nullable": true, + "description": "Maximum number of policies (null means unlimited)" + }, + "policy-mandatory-enforcement-limit": { + "type": "number", + "nullable": true, + "description": "Maximum number of mandatory enforcement policies (null means unlimited)" + }, + "policy-set-limit": { + "type": "number", + "nullable": true, + "description": "Maximum number of policy sets (null means unlimited)" + }, + "private-networking": { + "type": "boolean", + "description": "Whether the feature set includes private networking" + }, + "private-policy-agents": { + "type": "boolean", + "description": "Whether the feature set includes private policy agents" + }, + "private-run-tasks": { + "type": "boolean", + "description": "Whether the feature set includes private run tasks" + }, + "private-vcs": { + "type": "boolean", + "description": "Whether the feature set includes private VCS" + }, + "run-task-limit": { + "type": "number", + "nullable": true, + "description": "Maximum number of run tasks (null means unlimited)" + }, + "recoverable-items": { + "type": "boolean", + "description": "Whether the feature set allows enabling of recoverable items\n\nThis attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", + "x-vis": [ + "public-beta" + ] + }, + "run-task-mandatory-enforcement-limit": { + "type": "number", + "nullable": true, + "description": "Maximum number of mandatory enforcement run tasks (null means unlimited)" + }, + "run-task-workspace-limit": { + "type": "number", + "nullable": true, + "description": "Maximum number of workspaces per run task (null means unlimited)" + }, + "run-tasks": { + "type": "boolean", + "description": "Whether the feature set includes run tasks" + }, + "self-serve-billing": { + "type": "boolean", + "description": "Whether the feature set supports self-serve billing" + }, + "sentinel": { + "type": "boolean", + "description": "Whether the feature set includes Sentinel (alias for policy-enforcement)" + }, + "sso": { + "type": "boolean", + "description": "Whether the feature set includes SSO" + }, + "stacks": { + "type": "boolean", + "description": "Whether the feature set includes stacks" + }, + "teams": { + "type": "boolean", + "description": "Whether the feature set includes teams" + }, + "user-limit": { + "type": "number", + "nullable": true, + "description": "Maximum number of users (null means unlimited)" + }, + "uses-hcp-rum-billing-resource": { + "type": "boolean", + "description": "Whether the feature set uses HCP RUM billing resource" + }, + "versioned-policy-set-limit": { + "type": "number", + "nullable": true, + "description": "Maximum number of versioned policy sets (null means unlimited)" + }, + "waypoint-actions": { + "type": "boolean" + }, + "waypoint-templates-and-addons": { + "type": "boolean" + } + } + } + }, + "required": [ + "id", + "type", + "attributes" + ] + }, + "self-with-pagination": { + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "first": { + "type": "string" + }, + "prev": { + "type": "string", + "nullable": true + }, + "next": { + "type": "string", + "nullable": true + }, + "last": { + "type": "string" + } + } + }, + "pagination": { + "type": "object", + "properties": { + "current-page": { + "type": "integer" + }, + "page-size": { + "type": "integer" + }, + "prev-page": { + "type": "integer", + "nullable": true + }, + "next-page": { + "type": "integer", + "nullable": true + }, + "total-pages": { + "type": "integer" + }, + "total-count": { + "type": "integer" + } + } + }, + "organizations-id": { + "type": "object", + "properties": { + "data": { + "type": "object", + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "organizations" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "subscriptions-id": { + "type": "object", + "properties": { + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "subscriptions" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "subscriptions": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "subscriptions" + ] + }, + "attributes": { + "type": "object", + "properties": { + "end-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "is-active": { + "type": "boolean" + }, + "start-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "runs-ceiling": { + "type": "integer", + "nullable": true + }, + "agents-ceiling": { + "type": "integer", + "nullable": true + }, + "contract-start-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "contract-user-limit": { + "type": "integer", + "nullable": true + }, + "contract-apply-limit": { + "type": "integer", + "nullable": true + }, + "contract-managed-resources-limit": { + "type": "integer", + "nullable": true + }, + "hcp-organization-id": { + "type": "string", + "nullable": true + }, + "hcp-project-id": { + "type": "string", + "nullable": true + }, + "run-task-limit": { + "type": "integer", + "nullable": true + }, + "run-task-workspace-limit": { + "type": "integer", + "nullable": true + }, + "run-task-mandatory-enforcement-limit": { + "type": "integer", + "nullable": true + }, + "versioned-policy-set-limit": { + "type": "integer", + "nullable": true + }, + "policy-set-limit": { + "type": "integer", + "nullable": true + }, + "policy-limit": { + "type": "integer", + "nullable": true + }, + "policy-mandatory-enforcement-limit": { + "type": "integer", + "nullable": true + }, + "is-public-free-tier": { + "type": "boolean" + }, + "is-self-serve-trial": { + "type": "boolean" + }, + "is-change-approved": { + "type": "boolean" + }, + "free-apply-monthly-limit-starts-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "free-apply-monthly-limit": { + "type": "integer", + "nullable": true + }, + "free-apply-monthly-limit-remaining": { + "type": "integer", + "nullable": true + }, + "free-resource-under-management-monthly-limit": { + "type": "integer", + "nullable": true + }, + "rum-alert-threshold": { + "type": "integer", + "nullable": true, + "description": "The custom RUM usage alert threshold for the organization. When the organization's billable resource count meets or exceeds this value, an alert email is sent to org owners. Set to null to disable alerting. Only available on paid RUM plans.\n" + }, + "rum-threshold-alert-sent-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "Timestamp of the last time a RUM usage threshold alert was sent for the current rum-alert-threshold. Null when no alert has been sent for the current threshold.\n" + } + } + }, + "relationships": { + "type": "object", + "required": [ + "organization", + "feature-set" + ], + "properties": { + "organization": { + "$ref": "#/components/schemas/organizations-id" + }, + "feature-set": { + "$ref": "#/components/schemas/feature-sets-id" + }, + "hcp-billing-account": { + "$ref": "#/components/schemas/links_related" + }, + "next-subscription": { + "$ref": "#/components/schemas/subscriptions-id" + } + } + } + } + }, + "subscriptions-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/subscriptions" + } + } + }, + "billing-invoices": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The Stripe invoice ID." + }, + "type": { + "type": "string", + "enum": [ + "billing-invoices" + ], + "description": "The resource type identifier." + }, + "attributes": { + "type": "object", + "properties": { + "created-at": { + "type": "string", + "format": "date-time", + "description": "The date the invoice was created." + }, + "external-link": { + "type": "string", + "description": "A link to the Stripe-hosted invoice PDF." + }, + "number": { + "type": "string", + "description": "The invoice number." + }, + "paid": { + "type": "boolean", + "description": "Whether the invoice has been paid." + }, + "status": { + "type": "string", + "description": "The invoice status (e.g., \"paid\", \"draft\")." + }, + "total": { + "type": "integer", + "description": "The total invoice amount in cents." + } + } + } + } + }, + "agent-pools": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "agent-pools" + ] + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "created-at": { + "type": "string", + "format": "date-time", + "readOnly": true + }, + "organization-scoped": { + "type": "boolean" + }, + "agent-count": { + "type": "integer", + "readOnly": true + } + } + }, + "links": { + "$ref": "#/components/schemas/self" + }, + "relationships": { + "type": "object", + "properties": { + "agents": { + "$ref": "#/components/schemas/links_related" + }, + "authentication-tokens": { + "$ref": "#/components/schemas/links_related" + }, + "workspaces": { + "readOnly": true, + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "workspaces" + ] + } + } + } + } + } + }, + "allowed-workspaces": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "workspaces" + ] + } + } + } + } + } + } + } + } + } + }, + "agent-pools-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/agent-pools" + } + } + }, + "agents": { + "type": "object", + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "agents" + ] + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "status": { + "type": "string" + }, + "ip-address": { + "type": "string", + "nullable": true + }, + "last-ping-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "created-at": { + "type": "string", + "format": "date-time", + "readOnly": true + } + } + } + } + }, + "agents-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/agents" + } + } + }, + "agent-pools-id-many": { + "type": "object", + "nullable": true, + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "agent-pools" + ] + } + } + } + } + } + }, + "cidr-ranges-id-many": { + "type": "object", + "nullable": true, + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "cidr-ranges" + ] + } + } + } + } + } + }, + "cidr-range-lists": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "cidr-range-lists" + ] + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enforcement-scope": { + "type": "string", + "enum": [ + "organization", + "all_agent_pools", + "selected_agent_pools" + ] + }, + "updated-at": { + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "relationships": { + "type": "object", + "properties": { + "organization": { + "readOnly": true, + "$ref": "#/components/schemas/organizations-id" + }, + "agent-pools": { + "readOnly": true, + "$ref": "#/components/schemas/agent-pools-id-many" + }, + "cidr-ranges": { + "$ref": "#/components/schemas/cidr-ranges-id-many" + } + } + } + } + }, + "cidr-range-list-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/cidr-range-lists" + } + } + }, + "cidr-range-lists-id": { + "type": "object", + "nullable": true, + "required": [ + "data" + ], + "properties": { + "data": { + "type": "object", + "nullable": true, + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "cidr-range-lists" + ] + } + } + } + } + }, + "cidr-ranges": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "cidr-ranges" + ] + }, + "attributes": { + "type": "object", + "required": [ + "range", + "enabled" + ], + "properties": { + "range": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "enabled": { + "type": "boolean" + }, + "updated-at": { + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "relationships": { + "type": "object", + "properties": { + "organization": { + "readOnly": true, + "$ref": "#/components/schemas/organizations-id" + }, + "cidr-range-list": { + "readOnly": true, + "$ref": "#/components/schemas/cidr-range-lists-id" + } + } + } + } + }, + "cidr-ranges-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/cidr-ranges" + } + } + }, + "agent-pool-ids": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "type" + ], "properties": { - "status": { - "type": "string" - }, - "title": { + "id": { "type": "string" }, - "detail": { - "type": "string" + "type": { + "type": "string", + "enum": [ + "agent-pools" + ] + } + } + } + } + } + }, + "metrics-token": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "metrics-tokens" + ] + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the token." + }, + "token-id": { + "type": "string", + "readOnly": true, + "description": "The ID of the token." + }, + "created-at": { + "type": "string", + "format": "date-time", + "readOnly": true, + "description": "The time when the token was created." + }, + "expires-at": { + "type": "string", + "format": "date-time", + "readOnly": true, + "nullable": true, + "description": "The time when the token expires." + }, + "token": { + "type": "string", + "readOnly": true, + "nullable": true, + "description": "The secret text of the new authentication token. Only returned when the token is created." + } + } + } + } + }, + "agent-pools-id": { + "type": "object", + "nullable": true, + "required": [ + "data" + ], + "properties": { + "data": { + "type": "object", + "nullable": true, + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "agent-pools" + ] + } + } + } + } + }, + "data-retention-policy-id": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "object", + "nullable": true, + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "data-retention-policy-delete-olders", + "data-retention-policy-dont-deletes" + ] + } + } + } + } + }, + "entitlement-sets-id": { + "type": "object", + "properties": { + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "entitlement-sets" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "projects-id": { + "type": "object", + "properties": { + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "projects" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "hyok-configurations-id": { + "type": "object", + "properties": { + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "hyok-configurations" + ] + } + } + } + } + }, + "organizations": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "organizations" + ] + }, + "attributes": { + "type": "object", + "properties": { + "external-id": { + "type": "string", + "readOnly": true + }, + "created-at": { + "type": "string", + "format": "date-time", + "readOnly": true + }, + "email": { + "type": "string" + }, + "session-timeout": { + "type": "integer", + "nullable": true + }, + "session-remember": { + "type": "integer", + "nullable": true + }, + "collaborator-auth-policy": { + "type": "string", + "enum": [ + "password", + "two_factor_mandatory" + ] + }, + "plan-expired": { + "type": "boolean", + "readOnly": true + }, + "plan-expires-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "readOnly": true + }, + "plan-is-trial": { + "type": "boolean", + "readOnly": true + }, + "plan-is-enterprise": { + "type": "boolean", + "readOnly": true + }, + "plan-identifier": { + "type": "string", + "readOnly": true + }, + "cost-estimation-enabled": { + "type": "boolean" + }, + "send-passing-statuses-for-untriggered-speculative-plans": { + "type": "boolean" + }, + "aggregated-commit-status-enabled": { + "type": "boolean" + }, + "speculative-plan-management-enabled": { + "type": "boolean" + }, + "allow-force-delete-workspaces": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "hcp-id": { + "type": "string", + "readOnly": true, + "x-vis": [ + "hcpt" + ], + "description": "This attribute is only available in HCP Terraform." + }, + "is-unified": { + "type": "boolean", + "readOnly": true, + "x-vis": [ + "hcpt" + ], + "description": "This attribute is only available in HCP Terraform." + }, + "permissions": { + "type": "object", + "properties": { + "can-update": { + "type": "boolean" + }, + "can-update-authentication-token": { + "type": "boolean" + }, + "can-view-authentication": { + "type": "boolean" + }, + "can-destroy": { + "type": "boolean" + }, + "can-access-via-teams": { + "type": "boolean" + }, + "can-create-module": { + "type": "boolean" + }, + "can-create-team": { + "type": "boolean" + }, + "can-create-workspace": { + "type": "boolean" + }, + "can-manage-users": { + "type": "boolean" + }, + "can-view-users": { + "type": "boolean" + }, + "can-manage-subscription": { + "type": "boolean" + }, + "can-manage-sso": { + "type": "boolean" + }, + "can-update-oauth": { + "type": "boolean" + }, + "can-update-sentinel": { + "type": "boolean" + }, + "can-update-ssh-keys": { + "type": "boolean" + }, + "can-update-api-token": { + "type": "boolean" + }, + "can-traverse": { + "type": "boolean" + }, + "can-view-usage": { + "type": "boolean" + }, + "can-update-agent-pools": { + "type": "boolean" + }, + "can-manage-tags": { + "type": "boolean" + }, + "can-manage-varsets": { + "type": "boolean" + }, + "can-read-varsets": { + "type": "boolean" + }, + "can-manage-public-providers": { + "type": "boolean" + }, + "can-create-provider": { + "type": "boolean" + }, + "can-manage-public-modules": { + "type": "boolean" + }, + "can-manage-custom-providers": { + "type": "boolean" + }, + "can-manage-run-tasks": { + "type": "boolean" + }, + "can-read-run-tasks": { + "type": "boolean" + }, + "can-create-project": { + "type": "boolean" + }, + "can-enable-stacks": { + "type": "boolean" + }, + "can-manage-org-public-providers": { + "type": "boolean" + }, + "can-manage-org-public-modules": { + "type": "boolean" + }, + "can-manage-assessments": { + "type": "boolean" + }, + "can-read-assessments": { + "type": "boolean" + }, + "can-view-explorer": { + "type": "boolean" + }, + "can-deploy-no-code-modules": { + "type": "boolean" + }, + "can-manage-no-code-modules": { + "type": "boolean" + }, + "can-manage-groups-in-hcp": { + "type": "boolean", + "x-vis": [ + "hcpt" + ], + "description": "This attribute is only available in HCP Terraform." + }, + "can-create-project-in-hcp": { + "type": "boolean", + "x-vis": [ + "hcpt" + ], + "description": "This attribute is only available in HCP Terraform." + }, + "can-update-hyok-configuration": { + "type": "boolean", + "x-vis": [ + "hcpt" + ], + "description": "This attribute is only available in HCP Terraform." + }, + "can-manage-recoverable-items": { + "type": "boolean", + "x-vis": [ + "public-beta" + ], + "description": "This attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users." + }, + "can-read-policies": { + "type": "boolean", + "x-vis": [ + "tfe" + ], + "description": "This attribute is only available in Terraform Enterprise." + } + } + }, + "fair-run-queuing-enabled": { + "type": "boolean", + "readOnly": true + }, + "saml-enabled": { + "type": "boolean" + }, + "owners-team-saml-role-id": { + "type": "string", + "nullable": true + }, + "two-factor-conformant": { + "type": "boolean" + }, + "assessments-enforced": { + "type": "boolean" + }, + "is-in-degraded-mode": { + "type": "boolean", + "readOnly": true + }, + "global-module-sharing": { + "type": "boolean", + "x-vis": [ + "tfe" + ], + "description": "This attribute is only available in Terraform Enterprise." + }, + "global-provider-sharing": { + "type": "boolean", + "x-vis": [ + "tfe" + ], + "description": "This attribute is only available in Terraform Enterprise." + }, + "parent-data-retention-policy-info": { + "type": "string", + "readOnly": true, + "x-vis": [ + "tfe" + ], + "description": "This attribute is only available in Terraform Enterprise." + }, + "module-consuming-organizations-count": { + "type": "integer", + "readOnly": true, + "x-vis": [ + "tfe" + ], + "description": "This attribute is only available in Terraform Enterprise." + }, + "provider-consuming-organizations-count": { + "type": "integer", + "readOnly": true, + "x-vis": [ + "tfe" + ], + "description": "This attribute is only available in Terraform Enterprise." + }, + "remaining-testable-count": { + "type": "integer", + "readOnly": true + }, + "stacks-enabled": { + "type": "boolean", + "x-vis": [ + "public-beta" + ], + "description": "This attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users." + }, + "recoverable-items-enabled": { + "type": "boolean", + "x-vis": [ + "public-beta" + ], + "description": "This attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users." + }, + "over-stacks-resource-limit": { + "type": "boolean", + "readOnly": true, + "x-vis": [ + "public-beta" + ], + "description": "This attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users." + }, + "default-execution-mode": { + "type": "string", + "enum": [ + "remote", + "local", + "agent" + ] + }, + "stacks-default-execution-mode": { + "type": "string", + "enum": [ + "remote", + "agent" + ] + }, + "test-generation-enabled": { + "type": "boolean", + "readOnly": true, + "x-vis": [ + "public-beta" + ], + "description": "This attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users." + } + } + }, + "links": { + "$ref": "#/components/schemas/self" + }, + "relationships": { + "type": "object", + "properties": { + "default-agent-pool": { + "$ref": "#/components/schemas/agent-pools-id" + }, + "stacks-default-agent-pool": { + "$ref": "#/components/schemas/agent-pools-id" + }, + "data-retention-policy": { + "$ref": "#/components/schemas/data-retention-policy-id", + "x-vis": [ + "tfe" + ], + "description": "This relationship is only available in Terraform Enterprise." + }, + "module-producers": { + "x-vis": [ + "tfe" + ], + "$ref": "#/components/schemas/links_related", + "description": "This relationship is only available in Terraform Enterprise." + }, + "provider-producers": { + "x-vis": [ + "tfe" + ], + "$ref": "#/components/schemas/links_related", + "description": "This relationship is only available in Terraform Enterprise." + }, + "oauth-tokens": { + "$ref": "#/components/schemas/links_related" + }, + "authentication-token": { + "$ref": "#/components/schemas/links_related" + }, + "audit-trails-authentication-token": { + "$ref": "#/components/schemas/links_related", + "x-vis": [ + "hcpt" + ], + "description": "This relationship is only available in HCP Terraform." + }, + "entitlement-set": { + "$ref": "#/components/schemas/entitlement-sets-id" + }, + "subscription": { + "$ref": "#/components/schemas/subscriptions-id" + }, + "default-project": { + "$ref": "#/components/schemas/projects-id" + }, + "primary-hyok-configuration": { + "x-vis": [ + "hcpt" + ], + "$ref": "#/components/schemas/hyok-configurations-id", + "description": "This relationship is only available in HCP Terraform." + } + } + } + } + }, + "organizations-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/organizations" + } + } + }, + "projects": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "projects" + ] + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "created-at": { + "type": "string", + "format": "date-time", + "readOnly": true + }, + "auto-destroy-activity-duration": { + "type": "string", + "nullable": true + }, + "default-execution-mode": { + "type": "string", + "enum": [ + "remote", + "local", + "agent" + ] + }, + "stacks-default-execution-mode": { + "type": "string", + "enum": [ + "remote", + "agent" + ] + }, + "setting-overwrites": { + "type": "object", + "properties": { + "default-execution-mode": { + "type": "boolean" + }, + "default-agent-pool": { + "type": "boolean" + }, + "stacks-default-execution-mode": { + "type": "boolean" + }, + "stacks-default-agent-pool": { + "type": "boolean" + } + } + }, + "permissions": { + "type": "object", + "nullable": true, + "properties": { + "can-read": { + "type": "boolean" + }, + "can-update": { + "type": "boolean" + }, + "can-destroy": { + "type": "boolean" + }, + "can-create-workspace": { + "type": "boolean" + }, + "can-move-workspace": { + "type": "boolean" + }, + "can-move-stack": { + "type": "boolean" + }, + "can-manage-stacks": { + "type": "boolean" + }, + "can-view-stacks": { + "type": "boolean" + }, + "can-update-stacks": { + "type": "boolean" + }, + "can-deploy-no-code-modules": { + "type": "boolean" + }, + "can-read-teams": { + "type": "boolean" + }, + "can-manage-tags": { + "type": "boolean" + }, + "can-manage-teams": { + "type": "boolean" + }, + "can-manage-in-hcp": { + "type": "boolean", + "x-vis": [ + "hcpt" + ], + "description": "This attribute is only available in HCP Terraform." + }, + "can-manage-varsets": { + "type": "boolean" + }, + "can-manage-ephemeral-workspace-for-projects": { + "type": "boolean" + } + } + }, + "workspace-count": { + "type": "integer", + "nullable": true + }, + "team-count": { + "type": "integer", + "nullable": true + }, + "hcp-id": { + "type": "string", + "nullable": true, + "x-vis": [ + "hcpt" + ], + "description": "This attribute is only available in HCP Terraform." + }, + "is-unified": { + "type": "boolean", + "nullable": true, + "x-vis": [ + "hcpt" + ], + "description": "This attribute is only available in HCP Terraform." + } + } + }, + "relationships": { + "type": "object", + "properties": { + "organization": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/organizations-id" + }, + "links": { + "type": "object", + "properties": { + "related": { + "type": "string" + } + } + } + } + }, + "tag-bindings": { + "type": "object", + "nullable": true, + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "type": "string" + } + } + } + } + }, + "default-agent-pool": { + "$ref": "#/components/schemas/agent-pools-id" + }, + "stacks-default-agent-pool": { + "$ref": "#/components/schemas/agent-pools-id" + } + } + }, + "links": { + "type": "object", + "properties": { + "self": { + "type": "string" + } + } + } + } + }, + "entitlement-sets": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "entitlement-sets" + ] + }, + "attributes": { + "type": "object" + }, + "links": { + "type": "object" + } + } + }, + "cidr-range-list-with-ranges-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/cidr-range-lists" + } + } + }, + "status-counts": { + "type": "object", + "properties": { + "total": { + "type": "integer" + }, + "active": { + "type": "integer" + }, + "invited": { + "type": "integer" + } + } + }, + "organization-memberships": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true, + "description": "The organization membership ID" + }, + "type": { + "type": "string", + "enum": [ + "organization-memberships" + ] + }, + "attributes": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "active", + "invited", + "inactive" + ], + "readOnly": true, + "description": "The status of the organization membership. Can be \"active\", \"invited\", or \"inactive\"." + }, + "email": { + "type": "string", + "format": "email", + "description": "The email address of the user." + }, + "created-at": { + "type": "string", + "format": "date-time", + "readOnly": true, + "description": "The timestamp when the organization membership was created." + }, + "is-org-two-factor-required": { + "type": "boolean", + "nullable": true, + "readOnly": true, + "description": "Whether two-factor authentication is required for the organization. Only present for invited users." + } + } + }, + "relationships": { + "type": "object", + "properties": { + "teams": { + "type": "object", + "description": "The teams this user is a member of. Only shows teams the requesting user has access to, and teams that are not \"secret\" (unless the requester is a member).", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "teams" + ] + } + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "user": { + "type": "object", + "description": "The user associated with this organization membership.", + "properties": { + "data": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "users" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "organization": { + "type": "object", + "description": "The organization this membership belongs to.", + "properties": { + "data": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "organizations" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "scim-identity": { + "type": "object", + "description": "The SCIM identity associated with this organization membership.\nOnly available on HCP Terraform when SCIM is enabled.\nReturns null if the user has no SCIM identity for this organization.\n", + "properties": { + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "scim-identities" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + } + } + }, + "links": { + "$ref": "#/components/schemas/self-with-pagination" + }, + "meta": { + "type": "object", + "properties": { + "status-counts": { + "$ref": "#/components/schemas/status-counts" + }, + "pagination": { + "$ref": "#/components/schemas/pagination" + } + } + } + } + }, + "teams": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "teams" + ] + }, + "attributes": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the team, which can only include letters, numbers, `-`, and `_`." + }, + "users-count": { + "type": "integer", + "readOnly": true, + "description": "The number of active users in the team." + }, + "description": { + "type": "string", + "nullable": true, + "description": "Team description. Only available when effective permissions are enabled for unified organizations." + }, + "sso-team-id": { + "type": "string", + "nullable": true, + "description": "The unique identifier of the team from the SAML MemberOf attribute." + }, + "visibility": { + "type": "string", + "enum": [ + "secret", + "organization" + ], + "description": "The team's visibility. Can be \"secret\" or \"organization\" (visible)." + }, + "allow-member-token-management": { + "type": "boolean", + "description": "Whether team members are allowed to manage their own authentication tokens." + }, + "scim-linked": { + "type": "boolean", + "readOnly": true, + "description": "Whether this team is linked to a SCIM group. Only available when SCIM is enabled.\n\nThis attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", + "x-vis": [ + "public-beta" + ] + }, + "scim-group-name": { + "type": "string", + "nullable": true, + "readOnly": true, + "description": "The display name of the linked SCIM group. Only available when SCIM is enabled.\n\nThis attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", + "x-vis": [ + "public-beta" + ] + }, + "scim-updated-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "readOnly": true, + "description": "The timestamp of the most recent SCIM sync update for this team. Only available when SCIM is enabled.\n\nThis attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", + "x-vis": [ + "public-beta" + ] + }, + "scim-sync-paused": { + "type": "boolean", + "readOnly": true, + "description": "Whether SCIM sync is paused for this team. Only available when SCIM is enabled.\n\nThis attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", + "x-vis": [ + "public-beta" + ] + }, + "hcp-resource-name": { + "type": "string", + "nullable": true, + "readOnly": true, + "description": "The HCP resource name for unified teams.\n\nThis attribute is only available in HCP Terraform.", + "x-vis": [ + "hcpt" + ] + }, + "is-unified": { + "type": "boolean", + "readOnly": true, + "description": "Whether this team is unified with HCP.\n\nThis attribute is only available in HCP Terraform.", + "x-vis": [ + "hcpt" + ] + }, + "non-service-users-count": { + "type": "integer", + "nullable": true, + "readOnly": true, + "description": "The number of non-service account users in the team." + }, + "permissions": { + "type": "object", + "readOnly": true, + "description": "Permissions for the current user on this team.", + "properties": { + "can-update-membership": { + "type": "boolean" + }, + "can-destroy": { + "type": "boolean" + }, + "can-update-organization-access": { + "type": "boolean" + }, + "can-update-api-token": { + "type": "boolean" + }, + "can-update-visibility": { + "type": "boolean" + }, + "can-update-name": { + "type": "boolean" + }, + "can-update-sso-team-id": { + "type": "boolean" + }, + "can-update-member-token-management": { + "type": "boolean" + }, + "can-view-api-token": { + "type": "boolean" + } + } + }, + "organization-access": { + "type": "object", + "nullable": true, + "description": "Settings for the team's organization-level permissions.", + "properties": { + "manage-policies": { + "type": "boolean" + }, + "manage-workspaces": { + "type": "boolean" + }, + "manage-vcs-settings": { + "type": "boolean" + }, + "manage-policy-overrides": { + "type": "boolean" + }, + "delegate-policy-overrides": { + "type": "boolean" + }, + "manage-modules": { + "type": "boolean" + }, + "manage-providers": { + "type": "boolean" + }, + "manage-run-tasks": { + "type": "boolean" + }, + "manage-projects": { + "type": "boolean" + }, + "manage-membership": { + "type": "boolean" + }, + "manage-teams": { + "type": "boolean" + }, + "manage-organization-access": { + "type": "boolean" + }, + "access-secret-teams": { + "type": "boolean" + }, + "read-projects": { + "type": "boolean" + }, + "read-workspaces": { + "type": "boolean" + }, + "manage-agent-pools": { + "type": "boolean" + }, + "manage-public-providers": { + "type": "boolean", + "x-vis": [ + "hcpt" + ], + "description": "This attribute is only available in HCP Terraform." + }, + "manage-public-modules": { + "type": "boolean", + "x-vis": [ + "hcpt" + ], + "description": "This attribute is only available in HCP Terraform." + }, + "manage-registry-components": { + "type": "boolean", + "nullable": true + }, + "manage-registry-artifact-tags": { + "type": "boolean", + "nullable": true + }, + "manage-registry-artifact-version-tags": { + "type": "boolean", + "nullable": true + } + } + } + } + }, + "links": { + "$ref": "#/components/schemas/self" + }, + "relationships": { + "type": "object", + "properties": { + "organization": { + "$ref": "#/components/schemas/organizations-id" + }, + "users": { + "type": "object", + "description": "Team members (active users only).", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "users" + ] + } + } + } + }, + "links": { + "$ref": "#/components/schemas/links_related" + } + } + }, + "organization-memberships": { + "type": "object", + "description": "Organization memberships for team members.", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "organization-memberships" + ] + } + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } } + }, + "authentication-token": { + "$ref": "#/components/schemas/links_related" + }, + "authentication-tokens": { + "$ref": "#/components/schemas/links_related" } } } } }, - "related": { - "type": "object", - "properties": { - "related": { - "type": "string" - } - } - }, - "links_related": { + "scim-identities": { "type": "object", + "required": [ + "type", + "attributes" + ], "properties": { - "links": { - "$ref": "#/components/schemas/related" + "id": { + "type": "string", + "readOnly": true, + "description": "The external ID of the SCIM identity" + }, + "type": { + "type": "string", + "enum": [ + "scim-identities" + ] + }, + "attributes": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "provisioned", + "claimed" + ], + "readOnly": true, + "description": "The provisioning status of the user.\n- \"provisioned\": User was created via SCIM provisioning\n- \"claimed\": User claimed their account or existed before SCIM\n" + } + } } } }, - "self": { + "organization-memberships-envelope": { "type": "object", + "required": [ + "data" + ], "properties": { - "self": { - "type": "string" + "data": { + "$ref": "#/components/schemas/organization-memberships" } } }, - "users": { + "recoverable-items": { "type": "object", "required": [ "id", "type", - "attributes" + "attributes", + "relationships" ], "properties": { "id": { "type": "string", - "readOnly": true + "readOnly": true, + "description": "The ID of the recoverable item" }, "type": { "type": "string", "enum": [ - "users" + "recoverable-items" ] }, "attributes": { "type": "object", + "required": [ + "recoverable-name", + "deleted-at", + "expires-at", + "unmanaged-resources" + ], "properties": { - "username": { - "type": "string", - "nullable": true - }, - "is-service-account": { - "description": "Indicates whether this user is a synthetic user representing a team or organization.", - "type": "boolean" - }, - "avatar-url": { + "recoverable-name": { "type": "string", - "nullable": true - }, - "auth-method": { - "type": "string" - }, - "v2-only": { - "type": "boolean" - }, - "is-admin": { - "type": "boolean" - }, - "is-site-admin": { - "description": "Deprecated. Use is-admin.", - "type": "boolean" - }, - "is-sso-login": { - "type": "boolean" - }, - "is-confirmed": { - "type": "boolean" - }, - "is-unified": { - "type": "boolean" - }, - "is-sudo": { - "type": "boolean" - }, - "email": { - "type": "string" + "description": "The name of the recoverable resource" }, - "unconfirmed-email": { + "deleted-at": { "type": "string", - "nullable": true + "format": "date-time", + "description": "The timestamp when the resource was deleted (soft-deleted)" }, - "password": { + "expires-at": { "type": "string", - "nullable": true - }, - "enterprise-support": { - "type": "boolean" - }, - "has-linked-hcp": { - "type": "boolean" + "format": "date-time", + "description": "The timestamp when the recoverable item will be permanently deleted" }, - "has-git-hub-app-token": { - "type": "boolean" + "unmanaged-resources": { + "type": "integer", + "description": "The number of unmanaged resources (RUM) associated with the recoverable item" }, - "two-factor": { + "permanently-deleted-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "The timestamp when the resource was permanently deleted, if applicable" + } + } + }, + "relationships": { + "type": "object", + "required": [ + "project", + "recoverable" + ], + "properties": { + "project": { "type": "object", + "description": "The project this recoverable item belongs to", "properties": { - "enabled": { - "type": "boolean" + "data": { + "$ref": "#/components/schemas/projects-id" }, - "verified": { - "type": "boolean" + "links": { + "$ref": "#/components/schemas/related" } } }, - "permissions": { + "recoverable": { "type": "object", + "description": "The recoverable resource (can be a workspace or stack.)", "properties": { - "can-create-organization": { - "type": "boolean" - }, - "can-view-organizations": { - "type": "boolean" - }, - "can-view-settings": { - "type": "boolean" - }, - "can-view-smtp-settings": { - "type": "boolean" - }, - "can-view-twilio-settings": { - "type": "boolean" - }, - "can-view-saml-settings": { - "type": "boolean" - }, - "can-view-admin-workspaces": { - "type": "boolean" - }, - "can-view-admin-runs": { - "type": "boolean" - }, - "can-view-customization-settings": { - "type": "boolean" - }, - "can-view-cost-estimation-settings": { - "type": "boolean" - }, - "can-view-tool-versions": { - "type": "boolean" - }, - "can-create-tool-versions": { - "type": "boolean" - }, - "can-view-general-settings": { - "type": "boolean" - }, - "can-use-sql-runner": { - "type": "boolean" - }, - "can-view-profile": { - "type": "boolean" - }, - "can-change-email": { - "type": "boolean" - }, - "can-change-username": { - "type": "boolean" - }, - "can-change-password": { - "type": "boolean" - }, - "can-manage-sessions": { - "type": "boolean" - }, - "can-manage-user-tokens": { - "type": "boolean" - }, - "can-update-user": { - "type": "boolean" - }, - "can-reenable-2fa-by-unlinking": { - "type": "boolean", - "x-vis": [ - "hcpt" - ] + "data": { + "type": "object", + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "description": "The type of the recoverable resource (e.g., workspaces, stacks)", + "enum": [ + "workspaces", + "stacks" + ] + } + } }, - "can-manage-hcp-accounts": { - "type": "boolean", - "x-vis": [ - "hcpt" - ] + "links": { + "$ref": "#/components/schemas/related" } } } } + } + } + }, + "data-retention-policy": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "data-retention-policy-delete-olders", + "data-retention-policy-dont-deletes" + ] + }, + "attributes": { + "type": "object", + "properties": { + "deleteOlderThanNDays": { + "type": "integer" + } + } + }, + "links": { + "$ref": "#/components/schemas/self" }, "relationships": { "type": "object", "properties": { - "authentication-tokens": { - "$ref": "#/components/schemas/links_related" - }, - "github-app-oauth-tokens": { - "$ref": "#/components/schemas/links_related" - }, - "authenticated-resource": { + "target": { + "readOnly": true, "type": "object", "properties": { "data": { "type": "object", + "required": [ + "id", + "type" + ], "properties": { "id": { "type": "string" @@ -18349,497 +25660,241 @@ "type": "string", "enum": [ "organizations", - "runs", - "users", - "teams" + "workspaces" ] } } - }, - "links": { - "$ref": "#/components/schemas/related" } } } } - }, - "links": { - "$ref": "#/components/schemas/self" } } }, - "users-envelope": { + "data-retention-policy-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/users" + "$ref": "#/components/schemas/data-retention-policy" } } }, - "hcp-billing-accounts-id": { + "projects-envelope": { "type": "object", - "nullable": false, + "required": [ + "data" + ], "properties": { "data": { + "$ref": "#/components/schemas/projects" + } + } + }, + "token-ttl-policy": { + "type": "object", + "properties": { + "id": { + "type": "string", + "readOnly": true, + "description": "The token TTL policy ID" + }, + "type": { + "type": "string", + "enum": [ + "organization-token-ttl-policies" + ] + }, + "attributes": { "type": "object", - "required": [ - "id", - "type" - ], "properties": { - "id": { - "type": "string" - }, - "type": { + "token-type": { "type": "string", + "description": "The type of the token TTL policy", "enum": [ - "hcp-billing-account" - ] + "organization", + "team", + "user", + "audit_trails", + "metrics" + ], + "example": "organization" + }, + "max-ttl-ms": { + "type": "integer", + "description": "The maximum time-to-live for the token in milliseconds", + "example": 3600000 + }, + "created-at": { + "type": "string", + "format": "date-time", + "description": "When the policy was created" + }, + "updated-at": { + "type": "string", + "format": "date-time", + "description": "When the policy was last updated" } - } - }, - "links": { - "$ref": "#/components/schemas/related" + }, + "required": [ + "token-type", + "max-ttl-ms" + ] } } }, - "feature-sets-id": { + "token-ttl-policy-entry": { "type": "object", - "nullable": true, "required": [ - "data" + "token-type", + "max-ttl-ms" ], "properties": { - "data": { - "type": "object", - "required": [ - "id", - "type" + "token-type": { + "type": "string", + "description": "The type of the token TTL policy", + "enum": [ + "organization", + "team", + "user", + "audit_trails", + "metrics" ], - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "feature-sets" - ] - } - } + "example": "organization" + }, + "max-ttl-ms": { + "type": "integer", + "description": "The maximum time-to-live for the token in milliseconds", + "example": 3600000 } } }, - "hcp-organization": { + "token-ttl-policies": { "type": "object", "required": [ - "id", - "type", - "attributes", - "relationships" + "type" ], "properties": { - "id": { - "type": "string" - }, "type": { - "type": "string" + "type": "string", + "enum": [ + "organization-token-ttl-policies" + ] }, "attributes": { "type": "object", - "required": [ - "name", - "is-hcp-admin" - ], - "properties": { - "name": { - "type": "string" - }, - "hcp-owner-email": { - "type": "string", - "nullable": true - }, - "is-hcp-admin": { - "type": "boolean" - } - } - }, - "relationships": { - "type": "object", - "required": [ - "default-account", - "connected-plans" - ], "properties": { - "default-account": { - "$ref": "#/components/schemas/hcp-billing-accounts-id" - }, - "connected-plans": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/feature-sets-id" - } - } + "token-ttl-policies": { + "type": "array", + "items": { + "$ref": "#/components/schemas/token-ttl-policy-entry" } } } } } }, - "hcp-organization-envelope": { + "token-ttl-policies-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/hcp-organization" + "$ref": "#/components/schemas/token-ttl-policies" } } }, - "hcp-billing-account": { + "workspaces-identifier-array-document": { "type": "object", "required": [ - "id", - "type", - "attributes" + "data" ], "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string" - }, - "attributes": { - "type": "object", - "required": [ - "project-id", - "hcp-organization-name", - "hcp-organization-id", - "balance", - "card-brand", - "card-last4", - "card-exp-month", - "card-exp-year", - "account-type", - "status" - ], - "properties": { - "project-id": { - "type": "string" - }, - "hcp-organization-name": { - "type": "string" - }, - "hcp-organization-id": { - "type": "string" - }, - "balance": { - "type": "number" - }, - "card-brand": { - "type": "string" - }, - "card-last4": { - "type": "string" - }, - "card-exp-month": { - "type": "integer" - }, - "card-exp-year": { - "type": "integer" - }, - "account-type": { - "type": "string" - }, - "status": { - "type": "string" + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "type", + "id" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "workspaces" + ] + }, + "id": { + "type": "string" + } } } } } }, - "feature-sets": { + "tag-bindings": { "type": "object", + "required": [ + "type", + "attributes" + ], "properties": { "id": { "type": "string", - "description": "The ID of the feature set" + "readOnly": true, + "example": "tb-7AHdkTVXrmxiB8vQ" }, "type": { "type": "string", "enum": [ - "feature-sets" + "tag-bindings" ] }, "attributes": { "type": "object", + "required": [ + "key" + ], "properties": { - "assessments": { - "type": "boolean", - "description": "Whether the feature set includes assessments" - }, - "audit-logging": { - "type": "boolean", - "description": "Whether the feature set includes audit logging" - }, - "can-self-service-downgrade": { - "type": "boolean", - "description": "Whether the organization can self-service downgrade from this feature set" - }, - "change-requests": { - "type": "boolean", - "description": "Whether the feature set includes change requests" - }, - "cost": { - "type": "number", - "description": "The cost of the feature set in cents" - }, - "cost-estimation": { - "type": "boolean", - "description": "Whether the feature set includes cost estimation" - }, - "default-agents-ceiling": { - "type": "number", - "description": "Default maximum number of concurrent agents" - }, - "default-runs-ceiling": { - "type": "number", - "description": "Default maximum number of concurrent runs" - }, - "description": { - "type": "string", - "description": "Description of the feature set" - }, - "global-run-tasks": { - "type": "boolean", - "description": "Whether the feature set includes global run tasks" - }, - "hyok": { - "type": "boolean", - "description": "Whether the feature set includes Hold Your Own Key encryption" - }, - "identifier": { - "type": "string", - "description": "Unique identifier for the feature set" - }, - "terraform-actions": { - "type": "boolean", - "description": "Whether the feature set includes Terraform Actions features" - }, - "is-current": { - "type": "boolean", - "description": "Whether this is a current/active feature set" - }, - "is-free-tier": { - "type": "boolean", - "description": "Whether this is a free tier feature set" - }, - "is-managed-resource-plan": { - "type": "boolean", - "description": "Whether this is a managed resource plan" - }, - "module-deprecations": { - "type": "boolean", - "description": "Whether this feature set includes module deprecations" - }, - "module-revocations": { - "type": "boolean", - "description": "Whether this feature set includes module revocations" - }, - "module-tests-agent-support": { - "type": "boolean" - }, - "module-tests-generation": { - "type": "boolean", - "description": "Whether the feature set includes module test generation" - }, - "name": { - "type": "string", - "description": "Name of the feature set" - }, - "no-code-modules": { - "type": "boolean", - "description": "Whether the feature set includes no-code modules" - }, - "plan": { + "created-at": { "type": "string", - "nullable": true, - "description": "Associated plan ID" - }, - "policy-enforcement": { - "type": "boolean", - "description": "Whether the feature set includes policy enforcement" - }, - "policy-limit": { - "type": "number", - "nullable": true, - "description": "Maximum number of policies (null means unlimited)" - }, - "policy-mandatory-enforcement-limit": { - "type": "number", - "nullable": true, - "description": "Maximum number of mandatory enforcement policies (null means unlimited)" - }, - "policy-set-limit": { - "type": "number", - "nullable": true, - "description": "Maximum number of policy sets (null means unlimited)" - }, - "private-networking": { - "type": "boolean", - "description": "Whether the feature set includes private networking" - }, - "private-policy-agents": { - "type": "boolean", - "description": "Whether the feature set includes private policy agents" - }, - "private-run-tasks": { - "type": "boolean", - "description": "Whether the feature set includes private run tasks" - }, - "private-vcs": { - "type": "boolean", - "description": "Whether the feature set includes private VCS" - }, - "run-task-limit": { - "type": "number", - "nullable": true, - "description": "Maximum number of run tasks (null means unlimited)" - }, - "recoverable-items": { - "type": "boolean", - "description": "Whether the feature set allows enabling of recoverable items", - "x-vis": [ - "public-beta" - ] - }, - "run-task-mandatory-enforcement-limit": { - "type": "number", - "nullable": true, - "description": "Maximum number of mandatory enforcement run tasks (null means unlimited)" - }, - "run-task-workspace-limit": { - "type": "number", - "nullable": true, - "description": "Maximum number of workspaces per run task (null means unlimited)" - }, - "run-tasks": { - "type": "boolean", - "description": "Whether the feature set includes run tasks" - }, - "self-serve-billing": { - "type": "boolean", - "description": "Whether the feature set supports self-serve billing" - }, - "sentinel": { - "type": "boolean", - "description": "Whether the feature set includes Sentinel (alias for policy-enforcement)" - }, - "sso": { - "type": "boolean", - "description": "Whether the feature set includes SSO" - }, - "stacks": { - "type": "boolean", - "description": "Whether the feature set includes stacks" - }, - "teams": { - "type": "boolean", - "description": "Whether the feature set includes teams" - }, - "user-limit": { - "type": "number", - "nullable": true, - "description": "Maximum number of users (null means unlimited)" - }, - "uses-hcp-rum-billing-resource": { - "type": "boolean", - "description": "Whether the feature set uses HCP RUM billing resource" - }, - "versioned-policy-set-limit": { - "type": "number", - "nullable": true, - "description": "Maximum number of versioned policy sets (null means unlimited)" + "format": "date-time", + "nullable": true }, - "waypoint-actions": { - "type": "boolean" + "key": { + "type": "string" }, - "waypoint-templates-and-addons": { - "type": "boolean" + "value": { + "type": "string" } } } - }, - "required": [ - "id", - "type", - "attributes" - ] - }, - "self-with-pagination": { - "type": "object", - "properties": { - "self": { - "type": "string" - }, - "first": { - "type": "string" - }, - "prev": { - "type": "string", - "nullable": true - }, - "next": { - "type": "string", - "nullable": true - }, - "last": { - "type": "string" - } } }, - "pagination": { + "tag-bindings-collection": { "type": "object", + "required": [ + "data" + ], "properties": { - "current-page": { - "type": "integer" - }, - "page-size": { - "type": "integer" - }, - "prev-page": { - "type": "integer", - "nullable": true - }, - "next-page": { - "type": "integer", - "nullable": true - }, - "total-pages": { - "type": "integer" - }, - "total-count": { - "type": "integer" + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/tag-bindings" + } } } }, - "organizations-id": { + "runs-id": { "type": "object", "properties": { "data": { "type": "object", - "required": [ - "id", - "type" - ], + "nullable": true, "properties": { "id": { "type": "string" @@ -18847,17 +25902,14 @@ "type": { "type": "string", "enum": [ - "organizations" + "runs" ] } } - }, - "links": { - "$ref": "#/components/schemas/related" } } }, - "subscriptions-id": { + "vars-id": { "type": "object", "properties": { "data": { @@ -18869,21 +25921,17 @@ "type": { "type": "string", "enum": [ - "subscriptions" + "vars" ] } } - }, - "links": { - "$ref": "#/components/schemas/related" } } }, - "subscriptions": { + "workspaces": { "type": "object", "required": [ - "type", - "attributes" + "type" ], "properties": { "id": { @@ -18893,255 +25941,387 @@ "type": { "type": "string", "enum": [ - "subscriptions" + "workspaces" ] }, "attributes": { "type": "object", "properties": { - "end-at": { + "allow-destroy-plan": { + "type": "boolean" + }, + "auto-apply": { + "type": "boolean" + }, + "auto-apply-run-trigger": { + "type": "boolean" + }, + "auto-destroy-activity-duration": { + "type": "string", + "nullable": true + }, + "auto-destroy-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "auto-destroy-status": { + "type": "string", + "nullable": true + }, + "inherits-project-auto-destroy": { + "type": "boolean" + }, + "created-at": { + "type": "string", + "format": "date-time", + "readOnly": true + }, + "environment": { + "type": "string" + }, + "locked": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "queue-all-runs": { + "type": "boolean" + }, + "speculative-enabled": { + "type": "boolean" + }, + "structured-run-output-enabled": { + "type": "boolean" + }, + "terraform-version": { + "type": "string" + }, + "working-directory": { + "type": "string", + "nullable": true + }, + "global-remote-state": { + "type": "boolean" + }, + "project-remote-state": { + "type": "boolean" + }, + "updated-at": { + "type": "string", + "format": "date-time", + "readOnly": true + }, + "resource-count": { + "type": "integer" + }, + "apply-duration-average": { + "type": "integer", + "nullable": true + }, + "plan-duration-average": { + "type": "integer", + "nullable": true + }, + "policy-check-failures": { + "type": "integer", + "nullable": true + }, + "run-failures": { + "type": "integer", + "nullable": true + }, + "workspace-kpis-runs-count": { + "type": "integer", + "nullable": true + }, + "latest-change-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "operations": { + "type": "boolean", + "description": "Deprecated. Use execution-mode instead." + }, + "execution-mode": { + "type": "string", + "enum": [ + "remote", + "local", + "agent" + ] + }, + "setting-overwrites": { + "type": "object", + "properties": { + "execution-mode": { + "type": "boolean" + }, + "agent-pool": { + "type": "boolean" + } + } + }, + "vcs-repo": { + "type": "object", + "nullable": true, + "properties": { + "identifier": { + "type": "string" + }, + "display-identifier": { + "type": "string", + "nullable": true + }, + "branch": { + "type": "string", + "nullable": true + }, + "ingress-submodules": { + "type": "boolean" + }, + "oauth-token-id": { + "type": "string", + "nullable": true + }, + "github-app-installation-id": { + "type": "string", + "nullable": true + }, + "tags-regex": { + "type": "string", + "nullable": true + } + } + }, + "vcs-repo-identifier": { + "type": "string", + "nullable": true + }, + "permissions": { + "type": "object", + "nullable": true, + "properties": { + "can-update": { + "type": "boolean" + }, + "can-destroy": { + "type": "boolean" + }, + "can-queue-run": { + "type": "boolean" + }, + "can-read-run": { + "type": "boolean" + }, + "can-read-variable": { + "type": "boolean" + }, + "can-update-variable": { + "type": "boolean" + }, + "can-read-state-versions": { + "type": "boolean" + }, + "can-read-state-outputs": { + "type": "boolean" + }, + "can-create-state-versions": { + "type": "boolean" + }, + "can-queue-apply": { + "type": "boolean" + }, + "can-lock": { + "type": "boolean" + }, + "can-unlock": { + "type": "boolean" + }, + "can-force-unlock": { + "type": "boolean" + }, + "can-read-settings": { + "type": "boolean" + }, + "can-manage-tags": { + "type": "boolean" + }, + "can-manage-run-tasks": { + "type": "boolean" + }, + "can-force-delete": { + "type": "boolean" + }, + "can-manage-assessments": { + "type": "boolean" + }, + "can-manage-ephemeral-workspaces": { + "type": "boolean" + }, + "can-read-assessment-results": { + "type": "boolean" + }, + "can-queue-destroy": { + "type": "boolean" + } + } + }, + "actions": { + "type": "object", + "properties": { + "is-destroyable": { + "type": "boolean" + } + } + }, + "description": { "type": "string", - "format": "date-time", "nullable": true }, - "is-active": { + "file-triggers-enabled": { "type": "boolean" }, - "start-at": { - "type": "string", - "format": "date-time", - "nullable": true + "trigger-prefixes": { + "type": "array", + "nullable": true, + "items": { + "type": "string" + } }, - "runs-ceiling": { - "type": "integer", - "nullable": true + "trigger-patterns": { + "type": "array", + "nullable": true, + "items": { + "type": "string" + } }, - "agents-ceiling": { - "type": "integer", - "nullable": true + "assessments-enabled": { + "type": "boolean" }, - "contract-start-at": { + "last-assessment-result-at": { "type": "string", "format": "date-time", "nullable": true }, - "contract-user-limit": { - "type": "integer", - "nullable": true - }, - "contract-apply-limit": { - "type": "integer", - "nullable": true - }, - "contract-managed-resources-limit": { - "type": "integer", - "nullable": true - }, - "hcp-organization-id": { + "locked-reason": { "type": "string", "nullable": true }, - "hcp-project-id": { + "source": { "type": "string", "nullable": true }, - "run-task-limit": { - "type": "integer", - "nullable": true - }, - "run-task-workspace-limit": { - "type": "integer", - "nullable": true - }, - "run-task-mandatory-enforcement-limit": { - "type": "integer", - "nullable": true - }, - "versioned-policy-set-limit": { - "type": "integer", - "nullable": true - }, - "policy-set-limit": { - "type": "integer", - "nullable": true - }, - "policy-limit": { - "type": "integer", - "nullable": true - }, - "policy-mandatory-enforcement-limit": { - "type": "integer", - "nullable": true - }, - "is-public-free-tier": { - "type": "boolean" - }, - "is-self-serve-trial": { - "type": "boolean" - }, - "is-change-approved": { - "type": "boolean" - }, - "free-apply-monthly-limit-starts-at": { + "source-name": { "type": "string", - "format": "date-time", - "nullable": true - }, - "free-apply-monthly-limit": { - "type": "integer", - "nullable": true - }, - "free-apply-monthly-limit-remaining": { - "type": "integer", "nullable": true }, - "free-resource-under-management-monthly-limit": { - "type": "integer", + "source-url": { + "type": "string", "nullable": true - } - } - }, - "relationships": { - "type": "object", - "required": [ - "organization", - "feature-set" - ], - "properties": { - "organization": { - "$ref": "#/components/schemas/organizations-id" - }, - "feature-set": { - "$ref": "#/components/schemas/feature-sets-id" - }, - "hcp-billing-account": { - "$ref": "#/components/schemas/links_related" }, - "next-subscription": { - "$ref": "#/components/schemas/subscriptions-id" - } - } - } - } - }, - "subscriptions-envelope": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "$ref": "#/components/schemas/subscriptions" - } - } - }, - "billing-invoices": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "The Stripe invoice ID." - }, - "type": { - "type": "string", - "enum": [ - "billing-invoices" - ], - "description": "The resource type identifier." - }, - "attributes": { - "type": "object", - "properties": { - "created-at": { - "type": "string", - "format": "date-time", - "description": "The date the invoice was created." + "tag-names": { + "type": "array", + "items": { + "type": "string" + } }, - "external-link": { + "effective-state-version-retention-desc": { "type": "string", - "description": "A link to the Stripe-hosted invoice PDF." + "nullable": true, + "x-vis": [ + "tfe" + ], + "description": "A human-readable description of the effective state-version\nretention window for this workspace. Returns null when no state-version retention policy is in effect for the\nworkspace, or when the policy does not delete state versions.\n\n\nThis attribute is only available in Terraform Enterprise." }, - "number": { + "effective-run-data-retention-desc": { "type": "string", - "description": "The invoice number." + "nullable": true, + "x-vis": [ + "tfe" + ], + "description": "A human-readable description of the effective run data and logs\nretention window for this workspace. Returns null when no run data retention policy is in effect for the\nworkspace, or when the policy does not delete run data and logs.\n\n\nThis attribute is only available in Terraform Enterprise." }, - "paid": { + "hyok-enabled": { "type": "boolean", - "description": "Whether the invoice has been paid." - }, - "status": { - "type": "string", - "description": "The invoice status (e.g., \"paid\", \"draft\")." - }, - "total": { - "type": "integer", - "description": "The total invoice amount in cents." + "x-vis": [ + "hcpt" + ], + "description": "HCP Terraform Premium Tier only. Enabled Hold Your Own Key for the workspace. Once this has been set to true,\nit can no longer be disabled.\n\n\nThis attribute is only available in HCP Terraform." } } - } - } - }, - "agent-pools": { - "type": "object", - "required": [ - "type", - "attributes" - ], - "properties": { - "id": { - "type": "string", - "readOnly": true - }, - "type": { - "type": "string", - "enum": [ - "agent-pools" - ] }, - "attributes": { + "relationships": { "type": "object", "properties": { - "name": { - "type": "string" + "organization": { + "$ref": "#/components/schemas/organizations-id" }, - "created-at": { - "type": "string", - "format": "date-time", - "readOnly": true + "ssh-key": { + "type": "object", + "nullable": true, + "properties": { + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "ssh-keys" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } }, - "organization-scoped": { - "type": "boolean" + "locked-by": { + "type": "object", + "nullable": true, + "properties": { + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "users", + "teams", + "runs" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } }, - "agent-count": { - "type": "integer", - "readOnly": true - } - } - }, - "links": { - "$ref": "#/components/schemas/self" - }, - "relationships": { - "type": "object", - "properties": { - "agents": { - "$ref": "#/components/schemas/links_related" + "current-run": { + "$ref": "#/components/schemas/runs-id" }, - "authentication-tokens": { - "$ref": "#/components/schemas/links_related" + "latest-run": { + "$ref": "#/components/schemas/runs-id" }, - "workspaces": { - "readOnly": true, + "outputs": { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", - "required": [ - "id", - "type" - ], "properties": { "id": { "type": "string" @@ -19149,7 +26329,7 @@ "type": { "type": "string", "enum": [ - "workspaces" + "workspace-outputs" ] } } @@ -19157,169 +26337,134 @@ } } }, - "allowed-workspaces": { + "remote-state-consumers": { + "type": "object", + "properties": { + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "current-state-version": { "type": "object", + "nullable": true, "properties": { "data": { - "type": "array", - "items": { - "type": "object", - "required": [ - "id", - "type" - ], - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "workspaces" - ] - } + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "state-versions" + ] } } } } - } - } - } - } - }, - "agent-pools-envelope": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "$ref": "#/components/schemas/agent-pools" - } - } - }, - "agents": { - "type": "object", - "properties": { - "id": { - "type": "string", - "readOnly": true - }, - "type": { - "type": "string", - "enum": [ - "agents" - ] - }, - "attributes": { - "type": "object", - "properties": { - "name": { - "type": "string" }, - "status": { - "type": "string" + "current-configuration-version": { + "type": "object", + "nullable": true, + "properties": { + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "configuration-versions" + ] + } + } + } + } }, - "ip-address": { - "type": "string" + "agent-pool": { + "$ref": "#/components/schemas/agent-pools-id" }, - "last-ping-at": { - "type": "string", - "format": "date-time" + "readme": { + "type": "object", + "nullable": true, + "properties": { + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "workspace-readme" + ] + } + } + } + } }, - "created-at": { - "type": "string", - "format": "date-time", - "readOnly": true - } - } - } - } - }, - "agents-envelope": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "$ref": "#/components/schemas/agents" - } - } - }, - "agent-pools-id": { - "type": "object", - "nullable": true, - "required": [ - "data" - ], - "properties": { - "data": { - "type": "object", - "nullable": true, - "required": [ - "id", - "type" - ], - "properties": { - "id": { - "type": "string" + "project": { + "$ref": "#/components/schemas/projects-id" }, - "type": { - "type": "string", - "enum": [ - "agent-pools" - ] - } - } - } - } - }, - "entitlement-sets-id": { - "type": "object", - "properties": { - "data": { - "type": "object", - "properties": { - "id": { - "type": "string" + "current-assessment-result": { + "type": "object", + "nullable": true, + "properties": { + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "assessment-results" + ] + } + } + } + } }, - "type": { - "type": "string", - "enum": [ - "entitlement-sets" - ] + "vars": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/vars-id" + } + } + } } } }, "links": { - "$ref": "#/components/schemas/related" + "$ref": "#/components/schemas/self" } } }, - "projects-id": { + "workspaces-envelope": { "type": "object", + "required": [ + "data" + ], "properties": { "data": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "projects" - ] - } - } - }, - "links": { - "$ref": "#/components/schemas/related" + "$ref": "#/components/schemas/workspaces" } } }, - "organizations": { + "notification-configurations": { "type": "object", "required": [ "type", @@ -19333,495 +26478,481 @@ "type": { "type": "string", "enum": [ - "organizations" + "notification-configurations" ] }, "attributes": { "type": "object", + "required": [ + "name", + "destination-type", + "enabled" + ], "properties": { - "external-id": { - "type": "string", - "readOnly": true - }, - "created-at": { - "type": "string", - "format": "date-time", - "readOnly": true - }, - "email": { - "type": "string" - }, - "session-timeout": { - "type": "integer", - "nullable": true - }, - "session-remember": { - "type": "integer", - "nullable": true - }, - "collaborator-auth-policy": { - "type": "string", - "enum": [ - "password", - "two_factor_mandatory" - ] - }, - "plan-expired": { - "type": "boolean", - "readOnly": true - }, - "plan-expires-at": { - "type": "string", - "format": "date-time", - "nullable": true, - "readOnly": true - }, - "plan-is-trial": { - "type": "boolean", - "readOnly": true - }, - "plan-is-enterprise": { - "type": "boolean", - "readOnly": true - }, - "plan-identifier": { - "type": "string", - "readOnly": true - }, - "cost-estimation-enabled": { - "type": "boolean" - }, - "send-passing-statuses-for-untriggered-speculative-plans": { - "type": "boolean" - }, - "aggregated-commit-status-enabled": { - "type": "boolean" - }, - "speculative-plan-management-enabled": { - "type": "boolean" - }, - "allow-force-delete-workspaces": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "hcp-id": { - "type": "string", - "readOnly": true, - "x-vis": [ - "hcpt" - ] - }, - "is-unified": { - "type": "boolean", - "readOnly": true, - "x-vis": [ - "hcpt" - ] - }, - "permissions": { - "type": "object", - "properties": { - "can-update": { - "type": "boolean" - }, - "can-update-authentication-token": { - "type": "boolean" - }, - "can-destroy": { - "type": "boolean" - }, - "can-access-via-teams": { - "type": "boolean" - }, - "can-create-module": { - "type": "boolean" - }, - "can-create-team": { - "type": "boolean" - }, - "can-create-workspace": { - "type": "boolean" - }, - "can-manage-users": { - "type": "boolean" - }, - "can-manage-subscription": { - "type": "boolean" - }, - "can-manage-sso": { - "type": "boolean" - }, - "can-update-oauth": { - "type": "boolean" - }, - "can-update-sentinel": { - "type": "boolean" - }, - "can-update-ssh-keys": { - "type": "boolean" - }, - "can-update-api-token": { - "type": "boolean" - }, - "can-traverse": { - "type": "boolean" - }, - "can-view-usage": { - "type": "boolean" - }, - "can-update-agent-pools": { - "type": "boolean" - }, - "can-manage-tags": { - "type": "boolean" - }, - "can-manage-varsets": { - "type": "boolean" - }, - "can-read-varsets": { - "type": "boolean" - }, - "can-manage-public-providers": { - "type": "boolean" - }, - "can-create-provider": { - "type": "boolean" - }, - "can-manage-public-modules": { - "type": "boolean" - }, - "can-manage-custom-providers": { - "type": "boolean" - }, - "can-manage-run-tasks": { - "type": "boolean" - }, - "can-read-run-tasks": { - "type": "boolean" - }, - "can-create-project": { - "type": "boolean" - }, - "can-enable-stacks": { - "type": "boolean" - }, - "can-manage-org-public-providers": { - "type": "boolean" - }, - "can-manage-org-public-modules": { - "type": "boolean" - }, - "can-manage-assessments": { - "type": "boolean" - }, - "can-read-assessments": { - "type": "boolean" - }, - "can-view-explorer": { - "type": "boolean" - }, - "can-deploy-no-code-modules": { - "type": "boolean" - }, - "can-manage-no-code-modules": { - "type": "boolean" - }, - "can-manage-groups-in-hcp": { - "type": "boolean", - "x-vis": [ - "hcpt" - ] - }, - "can-create-project-in-hcp": { - "type": "boolean", - "x-vis": [ - "hcpt" - ] - }, - "can-manage-recoverable-items": { - "type": "boolean", - "x-vis": [ - "public-beta" - ] - } - } + "name": { + "type": "string", + "description": "The name of the notification configuration." }, - "fair-run-queuing-enabled": { + "destination-type": { + "type": "string", + "description": "The type of notification destination (e.g., email, slack, generic, microsoft-teams).", + "enum": [ + "email", + "slack", + "generic", + "microsoft-teams" + ] + }, + "enabled": { "type": "boolean", - "readOnly": true + "description": "Whether the notification configuration is enabled." }, - "saml-enabled": { - "type": "boolean" + "triggers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of trigger events for this notification." }, - "owners-team-saml-role-id": { + "url": { "type": "string", - "nullable": true + "nullable": true, + "description": "The webhook URL for non-email destinations." }, - "two-factor-conformant": { - "type": "boolean" + "token": { + "type": "string", + "nullable": true, + "writeOnly": true, + "description": "The authentication token for the webhook." }, - "assessments-enforced": { - "type": "boolean" + "email-addresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "description": "Email addresses for email-type notifications." }, - "is-in-degraded-mode": { - "type": "boolean", + "user-email-addresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "readOnly": true, + "description": "Email addresses of users associated with this notification." + }, + "external-email-addresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "readOnly": true, + "description": "External email addresses (not associated with users) for this notification." + }, + "delivery-responses": { + "type": "array", + "items": { + "type": "object" + }, + "readOnly": true, + "description": "Responses from notification delivery attempts." + }, + "created-at": { + "type": "string", + "format": "date-time", "readOnly": true }, - "remaining-testable-count": { - "type": "integer", + "updated-at": { + "type": "string", + "format": "date-time", "readOnly": true + } + } + }, + "relationships": { + "type": "object", + "properties": { + "subscribable": { + "type": "object", + "description": "The resource (workspace, project, or team) this notification is configured for.", + "properties": { + "data": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "workspaces", + "projects", + "teams", + "stacks" + ] + } + } + } + } }, - "stacks-enabled": { - "type": "boolean", - "x-vis": [ - "public-beta" - ] + "users": { + "type": "object", + "description": "Users associated with this notification (for email type).", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "users" + ] + } + } + } + } + } + } + } + } + } + }, + "notification-configurations-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/notification-configurations" + } + } + }, + "email-recipient-statuses": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "email-recipient-statuses" + ] + }, + "attributes": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "The email address of the recipient" }, - "recoverable-items-enabled": { - "type": "boolean", - "x-vis": [ - "public-beta" - ] + "verified-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "The timestamp when the email was verified" }, - "over-stacks-resource-limit": { - "type": "boolean", + "unsubscribed-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "The timestamp when the email was unsubscribed" + }, + "delivery-failures-count": { + "type": "integer", "readOnly": true, - "x-vis": [ - "public-beta" - ] + "description": "The number of delivery failures for this email" }, - "default-execution-mode": { + "created-at": { "type": "string", - "enum": [ - "remote", - "local", - "agent" - ] + "format": "date-time", + "readOnly": true }, - "stacks-default-execution-mode": { + "updated-at": { "type": "string", - "enum": [ - "remote", - "agent" - ] + "format": "date-time", + "readOnly": true + } + } + } + } + }, + "email-recipient-statuses-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/email-recipient-statuses" + } + } + }, + "workspaces-id": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "id": { + "type": "string" }, - "test-generation-enabled": { - "type": "boolean", - "readOnly": true, - "x-vis": [ - "public-beta" + "type": { + "type": "string", + "enum": [ + "workspaces" ] } } }, "links": { - "$ref": "#/components/schemas/self" - }, - "relationships": { + "$ref": "#/components/schemas/related" + } + } + }, + "users-id": { + "type": "object", + "properties": { + "data": { "type": "object", "properties": { - "default-agent-pool": { - "$ref": "#/components/schemas/agent-pools-id" - }, - "stacks-default-agent-pool": { - "$ref": "#/components/schemas/agent-pools-id" - }, - "oauth-tokens": { - "$ref": "#/components/schemas/links_related" - }, - "authentication-token": { - "$ref": "#/components/schemas/links_related" + "id": { + "type": "string" }, - "audit-trails-authentication-token": { - "$ref": "#/components/schemas/links_related", - "x-vis": [ - "hcpt" + "type": { + "type": "string", + "enum": [ + "users" ] - }, - "entitlement-set": { - "$ref": "#/components/schemas/entitlement-sets-id" - }, - "subscription": { - "$ref": "#/components/schemas/subscriptions-id" - }, - "default-project": { - "$ref": "#/components/schemas/projects-id" } } + }, + "links": { + "$ref": "#/components/schemas/related" } } }, - "organizations-envelope": { + "configuration-versions-id": { "type": "object", - "required": [ - "data" - ], "properties": { "data": { - "$ref": "#/components/schemas/organizations" + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "configuration-versions" + ] + } + } } } }, - "status-counts": { + "no-code-queries-id": { "type": "object", "properties": { - "total": { - "type": "integer" - }, - "active": { - "type": "integer" + "data": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "no-code-queries" + ] + } + } }, - "invited": { - "type": "integer" + "links": { + "$ref": "#/components/schemas/related" } } }, - "organization-memberships": { + "queries": { "type": "object", "required": [ "type", - "attributes" + "attributes", + "relationships" ], "properties": { "id": { "type": "string", - "readOnly": true, - "description": "The organization membership ID" + "readOnly": true }, "type": { "type": "string", "enum": [ - "organization-memberships" + "queries" ] }, "attributes": { "type": "object", "properties": { - "status": { - "type": "string", - "enum": [ - "active", - "invited", - "inactive" + "actions": { + "type": "object", + "required": [ + "is-cancelable", + "is-force-cancelable" ], - "readOnly": true, - "description": "The status of the organization membership. Can be \"active\", \"invited\", or \"inactive\"." + "properties": { + "is-cancelable": { + "type": "boolean" + }, + "is-force-cancelable": { + "type": "boolean" + } + } }, - "email": { + "canceled-at": { "type": "string", - "format": "email", - "description": "The email address of the user." + "format": "date-time", + "nullable": true, + "readOnly": true + }, + "updated-at": { + "type": "string", + "format": "date-time", + "readOnly": true }, "created-at": { "type": "string", "format": "date-time", - "readOnly": true, - "description": "The timestamp when the organization membership was created." + "readOnly": true }, - "is-org-two-factor-required": { - "type": "boolean", - "nullable": true, + "source": { + "type": "string", + "enum": [ + "tfe-api", + "tfe-ui", + "tfe-module", + "tfe-no-code-query", + "terraform" + ] + }, + "generate-config-out": { + "type": "boolean" + }, + "resources-discovered": { + "type": "integer", "readOnly": true, - "description": "Whether two-factor authentication is required for the organization. Only present for invited users." - } - } - }, - "relationships": { - "type": "object", - "properties": { - "teams": { - "type": "object", - "description": "The teams this user is a member of. Only shows teams the requesting user has access to, and teams that are not \"secret\" (unless the requester is a member).", - "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "teams" - ] - } - } - } - }, - "links": { - "$ref": "#/components/schemas/related" - } - } + "description": "The number of resources discovered by the query run." }, - "user": { + "status-timestamps": { "type": "object", - "description": "The user associated with this organization membership.", "properties": { - "data": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "users" - ] - } - } + "pending-at": { + "type": "string", + "format": "date-time" }, - "links": { - "$ref": "#/components/schemas/related" + "queued-at": { + "type": "string", + "format": "date-time" + }, + "errored-at": { + "type": "string", + "format": "date-time" + }, + "canceled-at": { + "type": "string", + "format": "date-time" + }, + "running-at": { + "type": "string", + "format": "date-time" + }, + "finished-at": { + "type": "string", + "format": "date-time" } } }, - "organization": { + "status": { + "type": "string", + "enum": [ + "pending", + "queued", + "running", + "finished", + "canceled", + "errored" + ] + }, + "log-read-url": { + "type": "string", + "readOnly": true + }, + "permissions": { "type": "object", - "description": "The organization this membership belongs to.", "properties": { - "data": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "organizations" - ] - } - } + "can-cancel": { + "type": "boolean" }, - "links": { - "$ref": "#/components/schemas/related" + "can-force-cancel": { + "type": "boolean" } } + }, + "force-cancel-available-at": { + "type": "string", + "format": "date-time", + "readOnly": true + }, + "policy-paths": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true } } }, - "links": { - "$ref": "#/components/schemas/self-with-pagination" - }, - "meta": { + "relationships": { "type": "object", + "required": [ + "workspace", + "configuration-version" + ], "properties": { - "status-counts": { - "$ref": "#/components/schemas/status-counts" + "workspace": { + "$ref": "#/components/schemas/workspaces-id" }, - "pagination": { - "$ref": "#/components/schemas/pagination" + "canceled-by": { + "$ref": "#/components/schemas/users-id" + }, + "configuration-version": { + "$ref": "#/components/schemas/configuration-versions-id" + }, + "created-by": { + "$ref": "#/components/schemas/users-id" + }, + "no-code-query": { + "$ref": "#/components/schemas/no-code-queries-id", + "description": "The no-code query that triggered this query run, if any." } } } } }, - "teams": { + "vars": { "type": "object", "required": [ "type", @@ -19835,375 +26966,306 @@ "type": { "type": "string", "enum": [ - "teams" + "vars" ] }, "attributes": { "type": "object", - "required": [ - "name" - ], "properties": { - "name": { - "type": "string", - "description": "The name of the team, which can only include letters, numbers, `-`, and `_`." - }, - "users-count": { - "type": "integer", - "readOnly": true, - "description": "The number of active users in the team." + "key": { + "type": "string" }, - "description": { + "value": { "type": "string", - "nullable": true, - "description": "Team description. Only available when effective permissions are enabled for unified organizations." + "nullable": true }, - "sso-team-id": { - "type": "string", - "nullable": true, - "description": "The unique identifier of the team from the SAML MemberOf attribute." + "sensitive": { + "type": "boolean" }, - "visibility": { + "category": { "type": "string", "enum": [ - "secret", - "organization" - ], - "description": "The team's visibility. Can be \"secret\" or \"organization\" (visible)." + "terraform", + "env", + "terraform-cloud", + "policy-set" + ] }, - "allow-member-token-management": { - "type": "boolean", - "description": "Whether team members are allowed to manage their own authentication tokens." + "hcl": { + "type": "boolean" }, - "hcp-resource-name": { + "created-at": { "type": "string", - "nullable": true, - "readOnly": true, - "description": "The HCP resource name for unified teams.", - "x-vis": [ - "hcpt" - ] + "format": "date-time", + "readOnly": true }, - "is-unified": { - "type": "boolean", - "readOnly": true, - "description": "Whether this team is unified with HCP.", - "x-vis": [ - "hcpt" - ] + "description": { + "type": "string", + "nullable": true }, - "non-service-users-count": { - "type": "integer", - "nullable": true, - "readOnly": true, - "description": "The number of non-service account users in the team." + "version-id": { + "type": "string" + } + } + }, + "relationships": { + "type": "object", + "properties": { + "configurable": { + "type": "object", + "properties": { + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "workspaces", + "policy-sets", + "varsets" + ] + } + } + } + } }, - "permissions": { + "varset": { "type": "object", - "readOnly": true, - "description": "Permissions for the current user on this team.", "properties": { - "can-update-membership": { - "type": "boolean" - }, - "can-destroy": { - "type": "boolean" - }, - "can-update-organization-access": { - "type": "boolean" - }, - "can-update-api-token": { - "type": "boolean" - }, - "can-update-visibility": { - "type": "boolean" - }, - "can-update-name": { - "type": "boolean" - }, - "can-update-sso-team-id": { - "type": "boolean" - }, - "can-update-member-token-management": { - "type": "boolean" + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "varsets" + ] + } + } }, - "can-view-api-token": { - "type": "boolean" + "links": { + "type": "object", + "properties": { + "related": { + "type": "string" + } + } } } }, - "organization-access": { + "workspace": { "type": "object", - "nullable": true, - "description": "Settings for the team's organization-level permissions.", "properties": { - "manage-policies": { - "type": "boolean" - }, - "manage-workspaces": { - "type": "boolean" - }, - "manage-vcs-settings": { - "type": "boolean" - }, - "manage-policy-overrides": { - "type": "boolean" - }, - "delegate-policy-overrides": { - "type": "boolean", - "description": "Whether the team can delegate policy override permissions. This field is available only when the `TEAM_OVERRIDE_POLICY_CHECKS` feature flag is enabled." - }, - "manage-modules": { - "type": "boolean" - }, - "manage-providers": { - "type": "boolean" - }, - "manage-run-tasks": { - "type": "boolean" - }, - "manage-projects": { - "type": "boolean" - }, - "manage-membership": { - "type": "boolean" - }, - "manage-teams": { - "type": "boolean" - }, - "manage-organization-access": { - "type": "boolean" - }, - "access-secret-teams": { - "type": "boolean" - }, - "read-projects": { - "type": "boolean" - }, - "read-workspaces": { - "type": "boolean" - }, - "manage-agent-pools": { - "type": "boolean" - }, - "manage-public-providers": { - "type": "boolean", - "x-vis": [ - "hcpt" - ] - }, - "manage-public-modules": { - "type": "boolean", - "x-vis": [ - "hcpt" - ] - }, - "manage-registry-components": { - "type": "boolean", - "nullable": true - }, - "manage-registry-artifact-tags": { - "type": "boolean", - "nullable": true + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "workspaces" + ] + } + } }, - "manage-registry-artifact-version-tags": { - "type": "boolean", - "nullable": true + "links": { + "type": "object", + "properties": { + "related": { + "type": "string" + } + } } } - } - } - }, - "links": { - "$ref": "#/components/schemas/self" - }, - "relationships": { - "type": "object", - "properties": { - "organization": { - "$ref": "#/components/schemas/organizations-id" }, - "users": { + "overwritten": { "type": "object", - "description": "Team members (active users only).", "properties": { "data": { "type": "array", "items": { - "type": "object", - "required": [ - "id", - "type" - ], - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "users" - ] - } - } + "$ref": "#/components/schemas/vars-id" } - }, - "links": { - "$ref": "#/components/schemas/links_related" } } }, - "organization-memberships": { + "overwriter": { "type": "object", - "description": "Organization memberships for team members.", "properties": { "data": { - "type": "array", - "items": { - "type": "object", - "required": [ - "id", - "type" - ], - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "organization-memberships" - ] - } + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "vars" + ] } } }, "links": { - "$ref": "#/components/schemas/related" + "type": "object", + "properties": { + "related": { + "type": "string" + } + } } } - }, - "authentication-token": { - "$ref": "#/components/schemas/links_related" - }, - "authentication-tokens": { - "$ref": "#/components/schemas/links_related" + } + } + }, + "links": { + "type": "object", + "properties": { + "self": { + "type": "string" } } } } }, - "organization-memberships-envelope": { + "vars-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/organization-memberships" + "$ref": "#/components/schemas/vars" } } }, - "recoverable-items": { + "provider-sets": { "type": "object", - "required": [ - "id", - "type", - "attributes", - "relationships" - ], "properties": { "id": { "type": "string", - "readOnly": true, - "description": "The ID of the recoverable item" + "readOnly": true }, "type": { "type": "string", "enum": [ - "recoverable-items" + "provider-sets" ] }, "attributes": { "type": "object", - "required": [ - "recoverable-name", - "deleted-at", - "expires-at", - "unmanaged-resources" - ], "properties": { - "recoverable-name": { + "name": { + "type": "string" + }, + "description": { "type": "string", - "description": "The name of the recoverable resource" + "nullable": true }, - "deleted-at": { + "global": { + "type": "boolean" + }, + "updated-at": { "type": "string", "format": "date-time", - "description": "The timestamp when the resource was deleted (soft-deleted)" + "readOnly": true }, - "expires-at": { + "created-at": { "type": "string", "format": "date-time", - "description": "The timestamp when the recoverable item will be permanently deleted" + "readOnly": true }, - "unmanaged-resources": { - "type": "integer", - "description": "The number of unmanaged resources (RUM) associated with the recoverable item" + "priority": { + "type": "boolean" }, - "permanently-deleted-at": { + "provider-source": { "type": "string", - "format": "date-time", - "nullable": true, - "description": "The timestamp when the resource was permanently deleted, if applicable" + "description": "Accepts either `{namespace}/{provider]` or `{hostname}/{namespace}/{provider}` Values are normalized to the fully qualified form.", + "pattern": "^(?:[A-Za-z0-9.-]+/)?[A-Za-z0-9-]+/[A-Za-z0-9-]+$", + "example": "registry.terraform.io/hashicorp/hcp" + }, + "configuration-hcl": { + "type": "string", + "example": "provider \"hcp\" {\n client_id = var.hcp_client_id\n}\n" } } }, "relationships": { "type": "object", - "required": [ - "project", - "recoverable" - ], "properties": { - "project": { - "type": "object", - "description": "The project this recoverable item belongs to", - "properties": { - "data": { - "$ref": "#/components/schemas/projects-id" - }, - "links": { - "$ref": "#/components/schemas/related" - } - } - }, - "recoverable": { + "organization": { "type": "object", - "description": "The recoverable resource (can be a workspace or stack.)", "properties": { "data": { "type": "object", - "required": [ - "id", - "type" - ], + "nullable": true, "properties": { "id": { "type": "string" }, "type": { "type": "string", - "description": "The type of the recoverable resource (e.g., workspaces, stacks)", "enum": [ - "workspaces", - "stacks" + "organizations" ] } } - }, - "links": { - "$ref": "#/components/schemas/related" + } + } + }, + "workspaces": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "workspaces" + ] + } + } + } + } + } + }, + "projects": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "projects" + ] + } + } + } } } } @@ -20211,47 +27273,57 @@ } } }, - "effective-tag-bindings-id": { + "provider-sets-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "type": "object", - "nullable": true, - "required": [ - "id", - "type" - ], - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "effective-tag-bindings" - ] + "$ref": "#/components/schemas/provider-sets" + } + } + }, + "projects-identifier-array-document": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "type", + "id" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "projects" + ] + }, + "id": { + "type": "string" + } } } } } }, - "projects": { + "varsets": { "type": "object", - "required": [ - "type", - "attributes" - ], "properties": { "id": { - "type": "string" + "type": "string", + "readOnly": true }, "type": { "type": "string", "enum": [ - "projects" + "varsets" ] }, "attributes": { @@ -20264,125 +27336,41 @@ "type": "string", "nullable": true }, - "created-at": { + "global": { + "type": "boolean" + }, + "updated-at": { "type": "string", "format": "date-time", "readOnly": true }, - "auto-destroy-activity-duration": { - "type": "string", - "nullable": true + "var-count": { + "type": "integer", + "readOnly": true }, - "default-execution-mode": { - "type": "string", - "enum": [ - "remote", - "local", - "agent" - ] + "workspace-count": { + "type": "integer", + "readOnly": true }, - "stacks-default-execution-mode": { - "type": "string", - "enum": [ - "remote", - "agent" - ] + "project-count": { + "type": "integer", + "readOnly": true }, - "setting-overwrites": { - "type": "object", - "properties": { - "default-execution-mode": { - "type": "boolean" - }, - "default-agent-pool": { - "type": "boolean" - }, - "stacks-default-execution-mode": { - "type": "boolean" - }, - "stacks-default-agent-pool": { - "type": "boolean" - } - } + "stack-count": { + "type": "integer", + "readOnly": true + }, + "priority": { + "type": "boolean" }, "permissions": { "type": "object", - "nullable": true, + "readOnly": true, "properties": { - "can-read": { - "type": "boolean" - }, "can-update": { "type": "boolean" - }, - "can-destroy": { - "type": "boolean" - }, - "can-create-workspace": { - "type": "boolean" - }, - "can-move-workspace": { - "type": "boolean" - }, - "can-move-stack": { - "type": "boolean" - }, - "can-manage-stacks": { - "type": "boolean" - }, - "can-view-stacks": { - "type": "boolean" - }, - "can-update-stacks": { - "type": "boolean" - }, - "can-deploy-no-code-modules": { - "type": "boolean" - }, - "can-read-teams": { - "type": "boolean" - }, - "can-manage-tags": { - "type": "boolean" - }, - "can-manage-teams": { - "type": "boolean" - }, - "can-manage-in-hcp": { - "type": "boolean", - "x-vis": [ - "hcpt" - ] - }, - "can-manage-varsets": { - "type": "boolean" - }, - "can-manage-ephemeral-workspace-for-projects": { - "type": "boolean" } } - }, - "workspace-count": { - "type": "integer", - "nullable": true - }, - "team-count": { - "type": "integer", - "nullable": true - }, - "hcp-id": { - "type": "string", - "nullable": true, - "x-vis": [ - "hcpt" - ] - }, - "is-unified": { - "type": "boolean", - "nullable": true, - "x-vis": [ - "hcpt" - ] } } }, @@ -20393,191 +27381,397 @@ "type": "object", "properties": { "data": { - "$ref": "#/components/schemas/organizations-id" - }, - "links": { "type": "object", + "nullable": true, "properties": { - "related": { + "id": { "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "organizations" + ] } } } } }, - "tag-bindings": { + "vars": { "type": "object", - "nullable": true, "properties": { - "links": { - "type": "object", - "properties": { - "related": { - "type": "string" + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "vars" + ] + }, + "attributes": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string", + "nullable": true + }, + "category": { + "type": "string", + "enum": [ + "terraform", + "env" + ] + } + } + } + } + } + } + } + }, + "workspaces": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "workspaces" + ] + } + } + } + } + } + }, + "projects": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "projects" + ] + } + } + } + } + } + }, + "stacks": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "stacks" + ] + } } } } } }, - "effective-tag-bindings": { + "parent": { "type": "object", - "nullable": true, "properties": { "data": { - "$ref": "#/components/schemas/effective-tag-bindings-id" - }, - "links": { "type": "object", + "nullable": true, "properties": { - "related": { + "id": { "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "organizations", + "projects" + ] } } } } - }, - "default-agent-pool": { - "$ref": "#/components/schemas/agent-pools-id" - }, - "stacks-default-agent-pool": { - "$ref": "#/components/schemas/agent-pools-id" } } + } + } + }, + "varsets-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/varsets" + } + } + }, + "jsonapi-resource-identifier": { + "type": "object", + "required": [ + "type", + "id" + ], + "properties": { + "type": { + "type": "string" }, - "links": { - "type": "object", - "properties": { - "self": { - "type": "string" - } - } + "id": { + "type": "string" } } }, - "projects-envelope": { + "jsonapi-identifier-array-document": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/projects" + "type": "array", + "items": { + "$ref": "#/components/schemas/jsonapi-resource-identifier" + } } } }, - "token-ttl-policy": { + "workspace-resource": { "type": "object", + "required": [ + "id", + "type", + "attributes" + ], "properties": { "id": { "type": "string", "readOnly": true, - "description": "The token TTL policy ID" + "description": "The ID of the workspace resource" }, "type": { "type": "string", "enum": [ - "organization-token-ttl-policies" + "resources" ] }, "attributes": { "type": "object", "properties": { - "token-type": { + "address": { "type": "string", - "description": "The type of the token TTL policy", - "enum": [ - "organization", - "team", - "user", - "audit_trails" - ], - "example": "organization" + "description": "The full address of the resource in Terraform configuration" }, - "max-ttl-ms": { - "type": "integer", - "description": "The maximum time-to-live for the token in milliseconds", - "example": 3600000 + "name": { + "type": "string", + "description": "The name of the resource" }, "created-at": { "type": "string", "format": "date-time", - "description": "When the policy was created" + "nullable": true, + "readOnly": true, + "description": "The timestamp when the resource was first created" }, "updated-at": { "type": "string", "format": "date-time", - "description": "When the policy was last updated" + "nullable": true, + "readOnly": true, + "description": "The timestamp when the resource was last updated" + }, + "module": { + "type": "string", + "nullable": true, + "description": "The module name where the resource is defined (e.g., \"root\" for root module)" + }, + "provider": { + "type": "string", + "nullable": true, + "description": "The provider name (e.g., \"hashicorp/random\")" + }, + "provider-type": { + "type": "string", + "nullable": true, + "description": "The resource type from the provider (e.g., \"random_pet\")" + }, + "modified-by-state-version-id": { + "type": "string", + "nullable": true, + "readOnly": true, + "description": "The ID of the state version that last modified this resource" + }, + "name-index": { + "type": "string", + "nullable": true, + "description": "The index of the resource when there are multiple instances with the same name" } - }, - "required": [ - "token-type", - "max-ttl-ms" - ] + } } } }, - "token-ttl-policy-entry": { + "action-reason": { "type": "object", - "required": [ - "token-type", - "max-ttl-ms" - ], "properties": { - "token-type": { + "reason": { "type": "string", - "description": "The type of the token TTL policy", - "enum": [ - "organization", - "team", - "user", - "audit_trails" - ], - "example": "organization" - }, - "max-ttl-ms": { - "type": "integer", - "description": "The maximum time-to-live for the token in milliseconds", - "example": 3600000 + "nullable": true, + "description": "An optional reason for locking the workspace." } } }, - "token-ttl-policies": { + "ssh-keys-nullable-identifier-document": { "type": "object", "required": [ - "type" + "data" ], "properties": { - "type": { - "type": "string", - "enum": [ - "organization-token-ttl-policies" - ] - }, - "attributes": { + "data": { "type": "object", + "nullable": true, "properties": { - "token-ttl-policies": { - "type": "array", - "items": { - "$ref": "#/components/schemas/token-ttl-policy-entry" + "type": { + "type": "string", + "enum": [ + "ssh-keys" + ] + }, + "id": { + "type": "string", + "nullable": true + } + } + } + } + }, + "workspace-vars-update-document": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "type", + "id" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "vars" + ] + }, + "id": { + "type": "string" + }, + "attributes": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string", + "nullable": true + }, + "sensitive": { + "type": "boolean" + }, + "category": { + "type": "string", + "enum": [ + "terraform", + "env" + ] + }, + "hcl": { + "type": "boolean" + }, + "description": { + "type": "string", + "nullable": true + } + } } } } } } }, - "token-ttl-policies-envelope": { + "tags-create-array-document": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/token-ttl-policies" + "type": "array", + "items": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "tags" + ] + }, + "id": { + "type": "string" + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + } + } + } } } }, - "workspaces-identifier-array-document": { + "tags-remove-array-document": { "type": "object", "required": [ "data" @@ -20595,7 +27789,7 @@ "type": { "type": "string", "enum": [ - "workspaces" + "tags" ] }, "id": { @@ -20606,99 +27800,7 @@ } } }, - "tag-bindings": { - "type": "object", - "required": [ - "type", - "attributes" - ], - "properties": { - "id": { - "type": "string", - "readOnly": true, - "example": "tb-7AHdkTVXrmxiB8vQ" - }, - "type": { - "type": "string", - "enum": [ - "tag-bindings" - ] - }, - "attributes": { - "type": "object", - "required": [ - "key" - ], - "properties": { - "created-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "key": { - "type": "string" - }, - "value": { - "type": "string" - } - } - } - } - }, - "tag-bindings-collection": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/tag-bindings" - } - } - } - }, - "runs-id": { - "type": "object", - "properties": { - "data": { - "type": "object", - "nullable": true, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "runs" - ] - } - } - } - } - }, - "vars-id": { - "type": "object", - "properties": { - "data": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "vars" - ] - } - } - } - } - }, - "workspaces": { + "state-versions": { "type": "object", "required": [ "type" @@ -20711,394 +27813,196 @@ "type": { "type": "string", "enum": [ - "workspaces" + "state-versions" ] }, "attributes": { "type": "object", "properties": { - "allow-destroy-plan": { - "type": "boolean" - }, - "auto-apply": { - "type": "boolean" - }, - "auto-apply-run-trigger": { - "type": "boolean" - }, - "auto-destroy-activity-duration": { - "type": "string", - "nullable": true - }, - "auto-destroy-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "auto-destroy-status": { - "type": "string", - "nullable": true - }, - "inherits-project-auto-destroy": { - "type": "boolean" - }, "created-at": { "type": "string", "format": "date-time", "readOnly": true }, - "environment": { - "type": "string" - }, - "locked": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "queue-all-runs": { - "type": "boolean" - }, - "speculative-enabled": { - "type": "boolean" - }, - "structured-run-output-enabled": { - "type": "boolean" - }, - "terraform-version": { - "type": "string" - }, - "working-directory": { - "type": "string", - "nullable": true - }, - "global-remote-state": { - "type": "boolean" - }, - "project-remote-state": { - "type": "boolean" - }, - "updated-at": { - "type": "string", - "format": "date-time", - "readOnly": true - }, - "resource-count": { - "type": "integer" - }, - "apply-duration-average": { - "type": "integer", - "nullable": true - }, - "plan-duration-average": { - "type": "integer", - "nullable": true - }, - "policy-check-failures": { - "type": "integer", - "nullable": true - }, - "run-failures": { - "type": "integer", - "nullable": true - }, - "workspace-kpis-runs-count": { + "size": { "type": "integer", - "nullable": true + "nullable": true, + "readOnly": true }, - "latest-change-at": { + "hosted-state-download-url": { "type": "string", - "format": "date-time", - "nullable": true - }, - "operations": { - "type": "boolean", - "description": "Deprecated. Use execution-mode instead." + "nullable": true, + "readOnly": true }, - "execution-mode": { + "hosted-json-state-download-url": { "type": "string", - "enum": [ - "remote", - "local", - "agent" - ] - }, - "setting-overwrites": { - "type": "object", - "properties": { - "execution-mode": { - "type": "boolean" - }, - "agent-pool": { - "type": "boolean" - } - } - }, - "vcs-repo": { - "type": "object", "nullable": true, - "properties": { - "identifier": { - "type": "string" - }, - "display-identifier": { - "type": "string", - "nullable": true - }, - "branch": { - "type": "string", - "nullable": true - }, - "ingress-submodules": { - "type": "boolean" - }, - "oauth-token-id": { - "type": "string", - "nullable": true - }, - "github-app-installation-id": { - "type": "string", - "nullable": true - }, - "tags-regex": { - "type": "string", - "nullable": true - } - } + "readOnly": true + }, + "hosted-state-upload-url": { + "type": "string", + "nullable": true, + "readOnly": true }, - "vcs-repo-identifier": { + "hosted-json-state-upload-url": { "type": "string", - "nullable": true + "nullable": true, + "readOnly": true }, - "permissions": { - "type": "object", + "encrypted-state-download-url": { + "type": "string", "nullable": true, - "properties": { - "can-update": { - "type": "boolean" - }, - "can-destroy": { - "type": "boolean" - }, - "can-queue-run": { - "type": "boolean" - }, - "can-read-run": { - "type": "boolean" - }, - "can-read-variable": { - "type": "boolean" - }, - "can-update-variable": { - "type": "boolean" - }, - "can-read-state-versions": { - "type": "boolean" - }, - "can-read-state-outputs": { - "type": "boolean" - }, - "can-create-state-versions": { - "type": "boolean" - }, - "can-queue-apply": { - "type": "boolean" - }, - "can-lock": { - "type": "boolean" - }, - "can-unlock": { - "type": "boolean" - }, - "can-force-unlock": { - "type": "boolean" - }, - "can-read-settings": { - "type": "boolean" - }, - "can-manage-tags": { - "type": "boolean" - }, - "can-manage-run-tasks": { - "type": "boolean" - }, - "can-force-delete": { - "type": "boolean" - }, - "can-manage-assessments": { - "type": "boolean" - }, - "can-manage-ephemeral-workspaces": { - "type": "boolean" - }, - "can-read-assessment-results": { - "type": "boolean" - }, - "can-queue-destroy": { - "type": "boolean" - } - } + "readOnly": true }, - "actions": { - "type": "object", - "properties": { - "is-destroyable": { - "type": "boolean" - } - } + "sanitized-state-download-url": { + "type": "string", + "nullable": true, + "readOnly": true }, - "description": { + "sanitized-state-upload-url": { "type": "string", - "nullable": true + "nullable": true, + "readOnly": true }, - "file-triggers-enabled": { - "type": "boolean" + "modules": { + "type": "object", + "nullable": true, + "readOnly": true, + "additionalProperties": true }, - "trigger-prefixes": { - "type": "array", + "providers": { + "type": "object", "nullable": true, - "items": { - "type": "string" - } + "readOnly": true, + "additionalProperties": true }, - "trigger-patterns": { + "resources": { "type": "array", "nullable": true, + "readOnly": true, "items": { - "type": "string" + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "count": { + "type": "integer" + }, + "module": { + "type": "string" + }, + "provider": { + "type": "string" + } + } } }, - "assessments-enabled": { - "type": "boolean" + "resources-processed": { + "type": "boolean", + "readOnly": true }, - "last-assessment-result-at": { + "serial": { + "type": "integer" + }, + "md5": { "type": "string", - "format": "date-time", - "nullable": true + "writeOnly": true }, - "locked-reason": { + "lineage": { "type": "string", - "nullable": true + "writeOnly": true }, - "source": { + "state": { "type": "string", - "nullable": true + "writeOnly": true }, - "source-name": { + "json-state": { "type": "string", - "nullable": true + "writeOnly": true }, - "source-url": { + "json-state-outputs": { "type": "string", - "nullable": true + "writeOnly": true }, - "tag-names": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "relationships": { - "type": "object", - "properties": { - "organization": { - "$ref": "#/components/schemas/organizations-id" + "force": { + "type": "boolean", + "writeOnly": true }, - "ssh-key": { - "type": "object", + "state-version": { + "type": "integer", "nullable": true, - "properties": { - "data": { - "type": "object", - "nullable": true, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "ssh-keys" - ] - } - } - }, - "links": { - "$ref": "#/components/schemas/related" - } - } + "readOnly": true }, - "locked-by": { - "type": "object", + "status": { + "type": "string", + "readOnly": true, + "enum": [ + "pending", + "finalized", + "discarded", + "backing_data_soft_deleted", + "backing_data_permanently_deleted" + ] + }, + "terraform-version": { + "type": "string", "nullable": true, - "properties": { - "data": { - "type": "object", - "nullable": true, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "users", - "teams", - "runs" - ] - } - } - }, - "links": { - "$ref": "#/components/schemas/related" - } - } + "readOnly": true }, - "current-run": { - "$ref": "#/components/schemas/runs-id" + "vcs-commit-url": { + "type": "string", + "nullable": true, + "readOnly": true }, - "latest-run": { - "$ref": "#/components/schemas/runs-id" + "vcs-commit-sha": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "intermediate": { + "type": "boolean", + "readOnly": true }, - "outputs": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "workspace-outputs" - ] - } - } - } - } - } + "billable-rum-count": { + "type": "integer", + "nullable": true, + "readOnly": true }, - "remote-state-consumers": { + "permissions": { "type": "object", + "readOnly": true, "properties": { - "links": { - "$ref": "#/components/schemas/related" + "can-restore-backing-data": { + "type": "boolean", + "readOnly": true } } + } + } + }, + "relationships": { + "type": "object", + "properties": { + "run": { + "$ref": "./stub/runs-id.yml" }, - "current-state-version": { + "rollback-state-version": { "type": "object", - "nullable": true, + "required": [ + "data" + ], "properties": { "data": { "type": "object", "nullable": true, + "required": [ + "id", + "type" + ], "properties": { "id": { "type": "string" @@ -21113,9 +28017,8 @@ } } }, - "current-configuration-version": { + "next-state-version": { "type": "object", - "nullable": true, "properties": { "data": { "type": "object", @@ -21127,19 +28030,15 @@ "type": { "type": "string", "enum": [ - "configuration-versions" + "state-versions" ] } } } } }, - "agent-pool": { - "$ref": "#/components/schemas/agent-pools-id" - }, - "readme": { + "previous-state-version": { "type": "object", - "nullable": true, "properties": { "data": { "type": "object", @@ -21151,19 +28050,21 @@ "type": { "type": "string", "enum": [ - "readmes" + "state-versions" ] } } } } }, - "project": { - "$ref": "#/components/schemas/projects-id" + "created-by": { + "$ref": "./stub/users-id.yml" }, - "current-assessment-result": { + "workspace": { + "$ref": "./stub/workspaces-id.yml" + }, + "hyok-encrypted-data-key": { "type": "object", - "nullable": true, "properties": { "data": { "type": "object", @@ -21175,158 +28076,149 @@ "type": { "type": "string", "enum": [ - "assessment-results" + "hyok-encrypted-data-keys" ] } } } } }, - "vars": { + "outputs": { "type": "object", "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/vars-id" + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "state-version-outputs" + ] + } + } } + }, + "links": { + "$ref": "./related.yml" } } - } - } - }, - "links": { + }, + "links": null + }, "$ref": "#/components/schemas/self" } } }, - "workspaces-envelope": { + "current-state-version-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/workspaces" + "$ref": "#/components/schemas/state-versions" + }, + "included": { + "type": "array", + "items": { + "type": "object" + } } } }, - "notification-configurations": { + "assessment-results": { "type": "object", "required": [ + "id", "type", "attributes" ], "properties": { "id": { "type": "string", - "readOnly": true + "example": "asmtres-8F5JFydVYAmtTjET" }, "type": { "type": "string", "enum": [ - "notification-configurations" + "assessment-results" ] }, "attributes": { "type": "object", - "required": [ - "name", - "destination-type", - "enabled" - ], "properties": { - "name": { - "type": "string", - "description": "The name of the notification configuration." - }, - "destination-type": { - "type": "string", - "description": "The type of notification destination (e.g., email, slack, generic, microsoft-teams).", - "enum": [ - "email", - "slack", - "generic", - "microsoft-teams" - ] - }, - "enabled": { + "succeeded": { "type": "boolean", - "description": "Whether the notification configuration is enabled." - }, - "triggers": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of trigger events for this notification." - }, - "url": { - "type": "string", - "nullable": true, - "description": "The webhook URL for non-email destinations." + "description": "Whether the assessment completed successfully" }, - "token": { - "type": "string", - "nullable": true, - "writeOnly": true, - "description": "The authentication token for the webhook." + "all-checks-succeeded": { + "type": "boolean", + "description": "Whether all health checks passed" }, - "email-addresses": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "description": "Email addresses for email-type notifications." + "checks-errored": { + "type": "integer", + "description": "Number of health checks that errored", + "nullable": true }, - "user-email-addresses": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "readOnly": true, - "description": "Email addresses of users associated with this notification." + "checks-failed": { + "type": "integer", + "description": "Number of health checks that failed", + "nullable": true }, - "external-email-addresses": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "readOnly": true, - "description": "External email addresses (not associated with users) for this notification." + "checks-passed": { + "type": "integer", + "description": "Number of health checks that passed", + "nullable": true }, - "delivery-responses": { - "type": "array", - "items": { - "type": "object" - }, - "readOnly": true, - "description": "Responses from notification delivery attempts." + "checks-unknown": { + "type": "integer", + "description": "Number of health checks with unknown status", + "nullable": true }, "created-at": { "type": "string", "format": "date-time", - "readOnly": true + "description": "Timestamp when the assessment result was created" }, - "updated-at": { + "drifted": { + "type": "boolean", + "description": "Whether drift was detected" + }, + "error-message": { "type": "string", - "format": "date-time", - "readOnly": true + "nullable": true, + "description": "Error message if the assessment failed" + }, + "resources-drifted": { + "type": "integer", + "nullable": true, + "description": "Number of resources that have drifted" + }, + "resources-undrifted": { + "type": "integer", + "nullable": true, + "description": "Number of resources that have not drifted" } } }, "relationships": { "type": "object", "properties": { - "subscribable": { + "workspace": { "type": "object", - "description": "The resource (workspace, project, or team) this notification is configured for.", + "description": "The workspace this assessment result belongs to", "properties": { "data": { "type": "object", + "required": [ + "id", + "type" + ], "properties": { "id": { "type": "string" @@ -21334,120 +28226,86 @@ "type": { "type": "string", "enum": [ - "workspaces", - "projects", - "teams" + "workspaces" ] } } } } }, - "users": { + "source": { "type": "object", - "description": "Users associated with this notification (for email type).", - "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "users" - ] - } + "description": "The source assessment or plan that produced this result.", + "properties": { + "data": { + "type": "object", + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string", + "example": "asmt-8F5JFydVYAmtTjET" + }, + "type": { + "type": "string", + "enum": [ + "assessments", + "plans" + ] } } } } } } - } - } - }, - "notification-configurations-envelope": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "$ref": "#/components/schemas/notification-configurations" - } - } - }, - "email-recipient-statuses": { - "type": "object", - "required": [ - "type", - "attributes" - ], - "properties": { - "id": { - "type": "string", - "readOnly": true - }, - "type": { - "type": "string", - "enum": [ - "email-recipient-statuses" - ] }, - "attributes": { + "links": { "type": "object", "properties": { - "email": { + "self": { "type": "string", - "description": "The email address of the recipient" + "description": "API URL for this assessment result" }, - "verified-at": { + "json-output": { "type": "string", - "format": "date-time", "nullable": true, - "description": "The timestamp when the email was verified" + "description": "API URL for the JSON formatted assessment output (available when assessment succeeded)" }, - "unsubscribed-at": { + "json-schema": { "type": "string", - "format": "date-time", "nullable": true, - "description": "The timestamp when the email was unsubscribed" - }, - "delivery-failures-count": { - "type": "integer", - "readOnly": true, - "description": "The number of delivery failures for this email" + "description": "API URL for the JSON schema of this assessment (available when assessment succeeded)" }, - "created-at": { + "sanitized-plan": { "type": "string", - "format": "date-time", - "readOnly": true + "nullable": true, + "description": "API URL for the sanitized plan (available when HYOK is enabled and assessment succeeded)", + "x-vis": [ + "public-beta" + ] }, - "updated-at": { + "log-output": { "type": "string", - "format": "date-time", - "readOnly": true + "description": "API URL to read the logs for this assessment" } } } } }, - "email-recipient-statuses-envelope": { + "assessment-results-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/email-recipient-statuses" + "$ref": "#/components/schemas/assessment-results" } } }, - "workspaces-id": { + "applies-id": { "type": "object", "properties": { "data": { @@ -21459,7 +28317,7 @@ "type": { "type": "string", "enum": [ - "workspaces" + "applies" ] } } @@ -21469,7 +28327,7 @@ } } }, - "users-id": { + "cost-estimates-id": { "type": "object", "properties": { "data": { @@ -21481,7 +28339,7 @@ "type": { "type": "string", "enum": [ - "users" + "cost-estimates" ] } } @@ -21491,7 +28349,7 @@ } } }, - "configuration-versions-id": { + "plans-id": { "type": "object", "properties": { "data": { @@ -21503,156 +28361,127 @@ "type": { "type": "string", "enum": [ - "configuration-versions" + "plans" ] } } + }, + "links": { + "$ref": "#/components/schemas/related" } } }, - "queries": { + "run-events-id": { "type": "object", - "required": [ - "type", - "attributes", - "relationships" - ], "properties": { - "id": { - "type": "string", - "readOnly": true - }, - "type": { - "type": "string", - "enum": [ - "queries" - ] - }, - "attributes": { + "data": { "type": "object", "properties": { - "actions": { - "type": "object", - "required": [ - "is-cancelable", - "is-force-cancelable" - ], - "properties": { - "is-cancelable": { - "type": "boolean" - }, - "is-force-cancelable": { - "type": "boolean" - } - } - }, - "canceled-at": { - "type": "string", - "format": "date-time", - "nullable": true, - "readOnly": true - }, - "updated-at": { - "type": "string", - "format": "date-time", - "readOnly": true + "id": { + "type": "string" }, - "created-at": { + "type": { "type": "string", - "format": "date-time", - "readOnly": true - }, - "source": { + "enum": [ + "run-events" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "task-stages-id": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "id": { "type": "string" }, - "generate-config-out": { - "type": "boolean" - }, - "status-timestamps": { - "type": "object", - "properties": { - "pending-at": { - "type": "string", - "format": "date-time" - }, - "queued-at": { - "type": "string", - "format": "date-time" - }, - "errored-at": { - "type": "string", - "format": "date-time" - }, - "canceled-at": { - "type": "string", - "format": "date-time" - }, - "running-at": { - "type": "string", - "format": "date-time" - }, - "finished-at": { - "type": "string", - "format": "date-time" - } - } - }, - "status": { + "type": { "type": "string", "enum": [ - "pending", - "running", - "finished", - "canceled", - "errored" + "task-stages" ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "policy-checks-id": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "id": { + "type": "string" }, - "log-read-url": { + "type": { "type": "string", - "readOnly": true - }, - "permissions": { - "type": "object", - "properties": { - "can-cancel": { - "type": "boolean" - }, - "can-force-cancel": { - "type": "boolean" - } - } + "enum": [ + "policy-checks" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "comments-id": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "id": { + "type": "string" }, - "force-cancel-available-at": { + "type": { "type": "string", - "format": "date-time", - "readOnly": true + "enum": [ + "workspace-comments" + ] } } }, - "relationships": { + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "tf-policy-evaluations-id": { + "type": "object", + "properties": { + "data": { "type": "object", - "required": [ - "workspace", - "configuration-version" - ], "properties": { - "workspace": { - "$ref": "#/components/schemas/workspaces-id" - }, - "canceled-by": { - "$ref": "#/components/schemas/users-id" - }, - "configuration-version": { - "$ref": "#/components/schemas/configuration-versions-id" + "id": { + "type": "string" }, - "created-by": { - "$ref": "#/components/schemas/users-id" + "type": { + "type": "string", + "enum": [ + "tf-policy-evaluations" + ] } } + }, + "links": { + "$ref": "#/components/schemas/related" } } }, - "vars": { + "runs": { "type": "object", "required": [ "type", @@ -21666,477 +28495,753 @@ "type": { "type": "string", "enum": [ - "vars" + "runs" ] }, "attributes": { "type": "object", "properties": { - "key": { - "type": "string" + "actions": { + "type": "object", + "properties": { + "is-cancelable": { + "type": "boolean" + }, + "is-confirmable": { + "type": "boolean" + }, + "is-discardable": { + "type": "boolean" + }, + "is-force-cancelable": { + "type": "boolean" + } + } }, - "value": { - "type": "string", - "nullable": true + "allow-config-generation": { + "type": "boolean" }, - "sensitive": { + "allow-empty-apply": { "type": "boolean" }, - "category": { + "auto-apply": { + "type": "boolean" + }, + "comment": { "type": "string", - "enum": [ - "terraform", - "env", - "terraform-cloud", - "policy-set" - ] + "writeOnly": true }, - "hcl": { - "type": "boolean" + "canceled-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "readOnly": true }, "created-at": { "type": "string", "format": "date-time", "readOnly": true }, - "description": { - "type": "string", + "debugging-mode": { + "type": "boolean" + }, + "has-changes": { + "type": "boolean" + }, + "is-destroy": { + "type": "boolean" + }, + "message": { + "type": "string" + }, + "plan-only": { + "type": "boolean" + }, + "refresh": { + "type": "boolean" + }, + "refresh-only": { + "type": "boolean" + }, + "replace-addrs": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true }, - "version-id": { + "save-plan": { + "type": "boolean" + }, + "source": { "type": "string" - } - } - }, - "relationships": { - "type": "object", - "properties": { - "configurable": { - "type": "object", - "properties": { - "data": { - "type": "object", - "nullable": true, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "workspaces", - "policy-sets", - "varsets" - ] - } - } - } - } }, - "varset": { + "status-timestamps": { "type": "object", "properties": { - "data": { - "type": "object", - "nullable": true, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "varsets" - ] - } - } + "fetching-at": { + "type": "string", + "format": "date-time" + }, + "fetched-at": { + "type": "string", + "format": "date-time" + }, + "pre-plan-running-at": { + "type": "string", + "format": "date-time" + }, + "pre-plan-completed-at": { + "type": "string", + "format": "date-time" + }, + "plan-queued-at": { + "type": "string", + "format": "date-time" + }, + "planning-at": { + "type": "string", + "format": "date-time" + }, + "planned-at": { + "type": "string", + "format": "date-time" + }, + "tf-policy-checked-at": { + "type": "string", + "format": "date-time", + "x-vis": [ + "public-beta" + ], + "description": "This attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users." + }, + "tf-policy-override-at": { + "type": "string", + "format": "date-time", + "x-vis": [ + "public-beta" + ], + "description": "This attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users." + }, + "post-plan-running-at": { + "type": "string", + "format": "date-time" + }, + "post-plan-completed-at": { + "type": "string", + "format": "date-time" + }, + "cost-estimating-at": { + "type": "string", + "format": "date-time" + }, + "cost-estimated-at": { + "type": "string", + "format": "date-time" + }, + "policy-soft-failed-at": { + "type": "string", + "format": "date-time" + }, + "policy-checked-at": { + "type": "string", + "format": "date-time" + }, + "confirmed-at": { + "type": "string", + "format": "date-time" + }, + "planned-and-finished-at": { + "type": "string", + "format": "date-time" + }, + "planned-and-saved-at": { + "type": "string", + "format": "date-time" + }, + "pre-apply-running-at": { + "type": "string", + "format": "date-time" + }, + "pre-apply-completed-at": { + "type": "string", + "format": "date-time" + }, + "apply-queued-at": { + "type": "string", + "format": "date-time" + }, + "applying-at": { + "type": "string", + "format": "date-time" }, - "links": { - "type": "object", - "properties": { - "related": { - "type": "string" - } - } - } - } - }, - "workspace": { - "type": "object", - "properties": { - "data": { - "type": "object", - "nullable": true, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "workspaces" - ] - } - } + "post-apply-completed-at": { + "type": "string", + "format": "date-time" }, - "links": { - "type": "object", - "properties": { - "related": { - "type": "string" - } - } - } - } - }, - "overwritten": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/vars-id" - } - } - } - }, - "overwriter": { - "type": "object", - "properties": { - "data": { - "type": "object", - "nullable": true, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "vars" - ] - } - } + "applied-at": { + "type": "string", + "format": "date-time" }, - "links": { - "type": "object", - "properties": { - "related": { - "type": "string" - } - } + "post-apply-running-at": { + "type": "string", + "format": "date-time" + }, + "discarded-at": { + "type": "string", + "format": "date-time" + }, + "errored-at": { + "type": "string", + "format": "date-time" + }, + "canceled-at": { + "type": "string", + "format": "date-time" + }, + "force-canceled-at": { + "type": "string", + "format": "date-time" + }, + "assessed-at": { + "type": "string", + "format": "date-time" + }, + "queuing-at": { + "type": "string", + "format": "date-time" + }, + "queuing-apply-at": { + "type": "string", + "format": "date-time" } } - } - } - }, - "links": { - "type": "object", - "properties": { - "self": { - "type": "string" - } - } - } - } - }, - "vars-envelope": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "$ref": "#/components/schemas/vars" - } - } - }, - "varsets": { - "type": "object", - "properties": { - "id": { - "type": "string", - "readOnly": true - }, - "type": { - "type": "string", - "enum": [ - "varsets" - ] - }, - "attributes": { - "type": "object", - "properties": { - "name": { - "type": "string" }, - "description": { + "status": { "type": "string", + "description": "The current status of the run.\n\n**Note:** The following status values are in public-beta:\n- `tf_policy_checked` - Terraform Policy evaluation completed at plan stage\n- `tf_policy_override` - Terraform Policy evaluation was overridden at plan stage\n", + "enum": [ + "pending", + "fetching", + "fetching_completed", + "pre_plan_running", + "pre_plan_completed", + "pre_plan_awaiting_decision", + "queuing", + "plan_queued", + "planning", + "planned", + "tf_policy_checked", + "tf_policy_override", + "post_plan_running", + "post_plan_completed", + "cost_estimating", + "cost_estimated", + "policy_checking", + "policy_override", + "policy_soft_failed", + "policy_checked", + "confirmed", + "pre_apply_running", + "pre_apply_completed", + "queuing_apply", + "apply_queued", + "applying", + "post_apply_running", + "post_apply_completed", + "applied", + "discarded", + "errored", + "canceled", + "planned_and_finished", + "planned_and_saved", + "assessing", + "assessed" + ] + }, + "target-addrs": { + "type": "array", + "items": { + "type": "string" + }, "nullable": true }, - "global": { - "type": "boolean" + "trigger-reason": { + "type": "string" + }, + "terraform-version": { + "type": "string" }, "updated-at": { "type": "string", "format": "date-time", "readOnly": true }, - "var-count": { - "type": "integer", - "readOnly": true - }, - "workspace-count": { - "type": "integer", - "readOnly": true - }, - "project-count": { - "type": "integer", - "readOnly": true + "triggering-source-name": { + "type": "string", + "nullable": true }, - "stack-count": { - "type": "integer", - "readOnly": true + "policy-paths": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true }, - "priority": { - "type": "boolean" + "invoke-action-addrs": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true }, "permissions": { "type": "object", - "readOnly": true, "properties": { - "can-update": { + "can-apply": { + "type": "boolean" + }, + "can-cancel": { + "type": "boolean" + }, + "can-comment": { + "type": "boolean" + }, + "can-discard": { + "type": "boolean" + }, + "can-force-execute": { + "type": "boolean" + }, + "can-force-cancel": { + "type": "boolean" + }, + "can-override-policy-check": { "type": "boolean" } } + }, + "variables": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + }, + "force-cancel-available-at": { + "type": "string", + "format": "date-time", + "readOnly": true } } }, "relationships": { "type": "object", "properties": { - "organization": { + "workspace": { + "$ref": "#/components/schemas/workspaces-id" + }, + "triggering-source": { + "$ref": "#/components/schemas/workspaces-id" + }, + "triggering-run": { + "$ref": "#/components/schemas/runs-id" + }, + "apply": { + "$ref": "#/components/schemas/applies-id" + }, + "canceled-by": { + "$ref": "#/components/schemas/users-id" + }, + "configuration-version": { + "$ref": "#/components/schemas/configuration-versions-id" + }, + "confirmed-by": { + "$ref": "#/components/schemas/users-id" + }, + "cost-estimate": { + "$ref": "#/components/schemas/cost-estimates-id" + }, + "created-by": { + "$ref": "#/components/schemas/users-id" + }, + "plan": { + "$ref": "#/components/schemas/plans-id" + }, + "run-events": { "type": "object", "properties": { "data": { - "type": "object", - "nullable": true, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "organizations" - ] - } + "type": "array", + "items": { + "$ref": "#/components/schemas/run-events-id" } } } }, - "vars": { + "task-stages": { "type": "object", "properties": { "data": { "type": "array", "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "vars" - ] - }, - "attributes": { - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "value": { - "type": "string", - "nullable": true - }, - "category": { - "type": "string", - "enum": [ - "terraform", - "env" - ] - } - } - } - } + "$ref": "#/components/schemas/task-stages-id" } } } }, - "workspaces": { + "policy-checks": { "type": "object", "properties": { "data": { "type": "array", "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "workspaces" - ] - } - } + "$ref": "#/components/schemas/policy-checks-id" } } } }, - "projects": { + "run-trigger-snapshots": { + "$ref": "#/components/schemas/related" + }, + "comments": { "type": "object", "properties": { "data": { "type": "array", "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "projects" - ] - } - } + "$ref": "#/components/schemas/comments-id" } } } }, - "stacks": { + "tf-policy-evaluations": { "type": "object", + "x-vis": [ + "public-beta" + ], "properties": { "data": { "type": "array", "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "stacks" - ] - } - } + "$ref": "#/components/schemas/tf-policy-evaluations-id" } } + }, + "description": "This relationship is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users." + } + } + } + } + }, + "runs-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/runs" + } + } + }, + "ingress-attributes-id": { + "type": "object", + "properties": { + "data": { + "nullable": true, + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "ingress-attributes" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "configuration-versions": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "configuration-versions" + ] + }, + "attributes": { + "type": "object", + "properties": { + "auto-queue-runs": { + "type": "boolean" + }, + "error": { + "type": "string", + "nullable": true + }, + "error-message": { + "type": "string", + "nullable": true + }, + "source": { + "type": "string", + "nullable": true + }, + "speculative": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": [ + "pending", + "fetching", + "uploaded", + "archived", + "errored", + "backing_data_soft_deleted", + "backing_data_permanently_deleted" + ] + }, + "status-timestamps": { + "type": "object", + "properties": { + "fetching-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "uploaded-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "errored-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "archived-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "soft-delete-backing-data-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "restore-backing-data-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "permanently-delete-backing-data-at": { + "type": "string", + "format": "date-time", + "nullable": true + } } }, - "parent": { - "type": "object", - "properties": { - "data": { - "type": "object", - "nullable": true, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "organizations", - "projects" - ] - } - } - } - } + "provisional": { + "type": "boolean" + }, + "upload-url": { + "type": "string", + "nullable": true, + "readOnly": true + } + } + }, + "relationships": { + "type": "object", + "properties": { + "ingress-attributes": { + "$ref": "#/components/schemas/ingress-attributes-id" + } + } + }, + "links": { + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "download": { + "type": "string" } } } } }, - "varsets-envelope": { + "configuration-versions-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/varsets" + "$ref": "#/components/schemas/configuration-versions" } } }, - "projects-identifier-array-document": { + "comments": { "type": "object", "required": [ - "data" + "type", + "attributes" ], "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "required": [ - "type", - "id" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "projects" - ] - }, - "id": { - "type": "string" - } + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "comments" + ] + }, + "attributes": { + "type": "object", + "properties": { + "body": { + "type": "string" + } + } + }, + "relationships": { + "type": "object", + "properties": { + "run-event": { + "$ref": "#/components/schemas/run-events-id" } } } } }, - "jsonapi-resource-identifier": { + "comments-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/comments" + } + } + }, + "action-comment": { + "type": "object", + "properties": { + "comment": { + "type": "string", + "nullable": true + } + } + }, + "run-triggers": { "type": "object", "required": [ "type", - "id" + "attributes" ], "properties": { + "id": { + "type": "string", + "readOnly": true + }, "type": { - "type": "string" + "type": "string", + "enum": [ + "run-triggers" + ] }, - "id": { - "type": "string" + "attributes": { + "type": "object", + "properties": { + "workspace-name": { + "type": "string" + }, + "sourceable-name": { + "type": "string" + }, + "created-at": { + "type": "string", + "format": "date-time", + "readOnly": true + } + } + }, + "relationships": { + "type": "object", + "properties": { + "workspace": { + "$ref": "#/components/schemas/workspaces-id" + }, + "sourceable": { + "$ref": "#/components/schemas/workspaces-id" + } + } + }, + "links": { + "$ref": "#/components/schemas/self" } } }, - "jsonapi-identifier-array-document": { + "run-triggers-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/jsonapi-resource-identifier" - } + "$ref": "#/components/schemas/run-triggers" } } }, - "workspace-resource": { + "pagination-without-totals": { + "type": "object", + "properties": { + "current-page": { + "type": "integer" + }, + "page-size": { + "type": "integer" + }, + "prev-page": { + "type": "integer", + "nullable": true + }, + "next-page": { + "type": "integer", + "nullable": true + } + } + }, + "plans": { "type": "object", "required": [ "id", @@ -22146,228 +29251,324 @@ "properties": { "id": { "type": "string", - "readOnly": true, - "description": "The ID of the workspace resource" + "example": "plan-8F5JFydVYAmtTjET" }, "type": { "type": "string", "enum": [ - "resources" + "plans" ] }, "attributes": { "type": "object", "properties": { - "address": { - "type": "string", - "description": "The full address of the resource in Terraform configuration" - }, - "name": { - "type": "string", - "description": "The name of the resource" + "execution-details": { + "type": "object", + "nullable": true, + "description": "Details about the execution of this plan. Null if plan has not started.", + "properties": { + "mode": { + "type": "string", + "description": "Execution mode of the run", + "enum": [ + "remote", + "agent", + "local" + ] + }, + "agent-id": { + "type": "string", + "example": "agent-S1Y7tcKxXPJDQAvq", + "description": "ID of the agent used for this run (when mode is agent)\n\nThis attribute is only available in HCP Terraform.", + "x-vis": [ + "hcpt" + ] + }, + "agent-name": { + "type": "string", + "example": "agent_01", + "description": "Name of the agent used for this run (when mode is agent)\n\nThis attribute is only available in HCP Terraform.", + "x-vis": [ + "hcpt" + ] + }, + "agent-pool-id": { + "type": "string", + "example": "apool-Zigq2VGreKq7nwph", + "description": "ID of the agent pool used for this run (when mode is agent)\n\nThis attribute is only available in HCP Terraform.", + "x-vis": [ + "hcpt" + ] + }, + "agent-pool-name": { + "type": "string", + "example": "first-pool", + "description": "Name of the agent pool used for this run (when mode is agent)\n\nThis attribute is only available in HCP Terraform.", + "x-vis": [ + "hcpt" + ] + } + } }, - "created-at": { - "type": "string", - "format": "date-time", + "generated-configuration": { + "type": "boolean", + "default": false, "nullable": true, - "readOnly": true, - "description": "The timestamp when the resource was first created" + "description": "Whether the plan generated new configuration as part of this run" }, - "updated-at": { - "type": "string", - "format": "date-time", - "nullable": true, - "readOnly": true, - "description": "The timestamp when the resource was last updated" + "has-changes": { + "type": "boolean", + "description": "Whether the plan has any changes" }, - "module": { - "type": "string", - "nullable": true, - "description": "The module name where the resource is defined (e.g., \"root\" for root module)" + "resource-additions": { + "type": "integer", + "description": "Number of resources that will be added", + "nullable": true }, - "provider": { - "type": "string", + "resource-changes": { + "type": "integer", + "description": "Number of resources that will be changed", + "nullable": true + }, + "resource-destructions": { + "type": "integer", + "description": "Number of resources that will be destroyed", + "nullable": true + }, + "resource-imports": { + "type": "integer", + "description": "Number of resources that will be imported", + "nullable": true + }, + "structured-run-output-enabled": { + "type": "boolean", "nullable": true, - "description": "The provider name (e.g., \"hashicorp/random\")" + "description": "Whether structured run output is enabled" }, - "provider-type": { + "status": { "type": "string", - "nullable": true, - "description": "The resource type from the provider (e.g., \"random_pet\")" + "description": "Current status of the plan", + "enum": [ + "pending", + "managed_queued", + "queued", + "running", + "errored", + "canceled", + "finished", + "unreachable" + ] }, - "modified-by-state-version-id": { + "status-timestamps": { + "type": "object", + "description": "Timestamps for state transitions of the plan", + "properties": { + "queued-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "pending-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "started-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "finished-at": { + "type": "string", + "format": "date-time", + "nullable": true + } + } + }, + "log-read-url": { "type": "string", "nullable": true, - "readOnly": true, - "description": "The ID of the state version that last modified this resource" + "description": "URL to read the logs for this plan" }, - "name-index": { - "type": "string", + "actions": { + "type": "object", + "description": "Actions available for this plan", + "properties": { + "is-exportable": { + "type": "boolean", + "description": "Whether the plan can be exported" + } + } + }, + "permissions": { + "type": "object", + "description": "Permissions for the current user related to this plan", "nullable": true, - "description": "The index of the resource when there are multiple instances with the same name" + "properties": { + "can-export": { + "type": "boolean", + "description": "Whether the current user can export the plan" + } + } } } - } - } - }, - "action-reason": { - "type": "object", - "properties": { - "reason": { - "type": "string", - "nullable": true, - "description": "An optional reason for locking the workspace." - } - } - }, - "ssh-keys-nullable-identifier-document": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { + }, + "relationships": { "type": "object", - "nullable": true, "properties": { - "type": { - "type": "string", - "enum": [ - "ssh-keys" - ] + "state-versions": { + "type": "object", + "description": "State versions associated with this plan (for TF <= 0.8)", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "state-versions" + ] + } + } + } + } + } }, - "id": { - "type": "string", - "nullable": true - } - } - } - } - }, - "workspace-vars-update-document": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "required": [ - "type", - "id" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "vars" - ] - }, - "id": { - "type": "string" - }, - "attributes": { - "type": "object", - "properties": { - "key": { - "type": "string" - }, - "value": { - "type": "string", - "nullable": true - }, - "sensitive": { - "type": "boolean" - }, - "category": { - "type": "string", - "enum": [ - "terraform", - "env" - ] - }, - "hcl": { - "type": "boolean" - }, - "description": { - "type": "string", - "nullable": true + "exports": { + "type": "object", + "description": "Exports associated with this plan", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "plan-exports" + ] + } + } + } + } + } + }, + "hyok-encrypted-data-key": { + "type": "object", + "description": "HYOK encrypted data key associated with this plan\n\nThis relationship is only available in HCP Terraform.", + "nullable": true, + "x-vis": [ + "hcpt" + ], + "properties": { + "data": { + "type": "object", + "nullable": true, + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "hyok-encrypted-data-keys" + ] + } } } } } } + }, + "links": { + "type": "object", + "properties": { + "self": { + "type": "string", + "description": "API URL for this plan" + }, + "json-output": { + "type": "string", + "nullable": true, + "description": "API URL for the JSON formatted execution plan (available for Terraform 0.12+)" + }, + "json-output-redacted": { + "type": "string", + "nullable": true, + "description": "API URL for the redacted JSON formatted execution plan (available for Terraform 0.15.2+)" + }, + "json-schema": { + "type": "string", + "nullable": true, + "description": "API URL for the JSON schema of this plan (available for Terraform 0.12+)" + }, + "sanitized-plan": { + "type": "string", + "nullable": true, + "description": "API URL for the sanitized plan (available when HYOK is enabled and with compatible Terraform version)", + "x-vis": [ + "public-beta" + ] + } + } } } }, - "tags-create-array-document": { + "plans-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "type": "array", - "items": { - "type": "object", - "required": [ - "type" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "tags" - ] - }, - "id": { - "type": "string" - }, - "attributes": { - "type": "object", - "properties": { - "name": { - "type": "string" - } - } - } - } - } + "$ref": "#/components/schemas/plans" } } }, - "tags-remove-array-document": { + "policy-sets-id": { "type": "object", - "required": [ - "data" - ], "properties": { "data": { - "type": "array", - "items": { - "type": "object", - "required": [ - "type", - "id" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "tags" - ] - }, - "id": { - "type": "string" - } + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "policy-sets" + ] } } + }, + "links": { + "$ref": "#/components/schemas/related" } } }, - "state-versions": { + "policies": { "type": "object", "required": [ "type" @@ -22380,411 +29581,512 @@ "type": { "type": "string", "enum": [ - "state-versions" + "policies" ] }, "attributes": { "type": "object", - "properties": { - "created-at": { - "type": "string", - "format": "date-time", - "readOnly": true - }, - "size": { - "type": "integer", - "nullable": true, - "readOnly": true - }, - "hosted-state-download-url": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "hosted-json-state-download-url": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "hosted-state-upload-url": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "hosted-json-state-upload-url": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "encrypted-state-download-url": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "sanitized-state-download-url": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "sanitized-state-upload-url": { - "type": "string", - "nullable": true, - "readOnly": true - }, - "modules": { - "type": "object", - "nullable": true, - "readOnly": true, - "additionalProperties": true - }, - "providers": { - "type": "object", - "nullable": true, - "readOnly": true, - "additionalProperties": true - }, - "resources": { - "type": "array", - "nullable": true, - "readOnly": true, - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "type": { - "type": "string" - }, - "count": { - "type": "integer" - }, - "module": { - "type": "string" - }, - "provider": { - "type": "string" - } - } - } - }, - "resources-processed": { - "type": "boolean", - "readOnly": true - }, - "serial": { - "type": "integer" - }, - "md5": { - "type": "string", - "writeOnly": true - }, - "lineage": { - "type": "string", - "writeOnly": true - }, - "state": { - "type": "string", - "writeOnly": true - }, - "json-state": { - "type": "string", - "writeOnly": true - }, - "json-state-outputs": { - "type": "string", - "writeOnly": true - }, - "force": { - "type": "boolean", - "writeOnly": true - }, - "state-version": { - "type": "integer", - "nullable": true, - "readOnly": true - }, - "status": { - "type": "string", - "readOnly": true, - "enum": [ - "pending", - "finalized", - "discarded", - "backing_data_soft_deleted", - "backing_data_permanently_deleted" - ] + "properties": { + "name": { + "type": "string", + "description": "The name of the policy." }, - "terraform-version": { + "description": { "type": "string", "nullable": true, - "readOnly": true + "description": "Text describing the policy's purpose. Supports Markdown." }, - "vcs-commit-url": { + "kind": { "type": "string", - "nullable": true, - "readOnly": true + "enum": [ + "sentinel", + "opa" + ], + "description": "The policy-as-code framework for the policy." }, - "vcs-commit-sha": { + "query": { "type": "string", "nullable": true, - "readOnly": true + "description": "The OPA query to run. Only present for OPA policies." }, - "intermediate": { - "type": "boolean", - "readOnly": true + "enforcement-level": { + "type": "string", + "enum": [ + "hard-mandatory", + "soft-mandatory", + "advisory", + "mandatory" + ], + "description": "The enforcement level of the policy. For Sentinel, valid values are hard-mandatory, soft-mandatory, and advisory. For OPA, valid values are mandatory and advisory." }, - "billable-rum-count": { + "enforce": { + "type": "array", + "description": "DEPRECATED: Use enforcement-level instead. An array of enforcement configurations mapping policy file paths to their enforcement modes.", + "items": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "mode": { + "type": "string" + } + } + } + }, + "policy-set-count": { "type": "integer", + "readOnly": true, + "description": "The number of policy sets that include this policy." + }, + "updated-at": { + "type": "string", + "format": "date-time", "nullable": true, - "readOnly": true + "readOnly": true, + "description": "The time of the most recent policy code upload." } } }, "relationships": { "type": "object", "properties": { - "run": { - "$ref": "./stub/runs-id.yml" + "organization": { + "$ref": "#/components/schemas/organizations-id" }, - "rollback-state-version": { + "policy-sets": { "type": "object", - "required": [ - "data" - ], "properties": { "data": { - "type": "object", - "nullable": true, - "required": [ - "id", - "type" - ], - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "state-versions" - ] - } + "type": "array", + "items": { + "$ref": "#/components/schemas/policy-sets-id" } } } - }, - "next-state-version": { + } + } + } + } + }, + "policies-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/policies" + } + } + }, + "policy-checks": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "policy-checks" + ] + }, + "attributes": { + "type": "object", + "properties": { + "result": { "type": "object", + "nullable": true, + "description": "The result of the policy evaluation. Null until the policy check completes. The `sentinel` key contains low-level Sentinel details and its structure may change over time.", "properties": { - "data": { + "result": { + "type": "boolean" + }, + "passed": { + "type": "integer" + }, + "total-failed": { + "type": "integer" + }, + "hard-failed": { + "type": "integer" + }, + "soft-failed": { + "type": "integer" + }, + "advisory-failed": { + "type": "integer" + }, + "duration-ms": { + "type": "integer" + }, + "sentinel": { "type": "object", - "nullable": true, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "state-versions" - ] - } - } + "additionalProperties": true, + "nullable": true } } }, - "previous-state-version": { + "scope": { + "type": "string", + "description": "The scope of policies evaluated in this check (e.g. \"organization\")." + }, + "status": { + "type": "string", + "enum": [ + "pending", + "queued", + "passed", + "soft_failed", + "hard_failed", + "overridden", + "errored", + "canceled", + "unreachable" + ] + }, + "status-timestamps": { "type": "object", "properties": { - "data": { - "type": "object", - "nullable": true, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "state-versions" - ] - } - } + "queued-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "passed-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "soft-failed-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "hard-failed-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "overridden-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "errored-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "canceled-at": { + "type": "string", + "format": "date-time", + "nullable": true } } }, - "created-by": { - "$ref": "./stub/users-id.yml" - }, - "workspace": { - "$ref": "./stub/workspaces-id.yml" - }, - "hyok-encrypted-data-key": { + "actions": { "type": "object", - "properties": { - "data": { - "type": "object", - "nullable": true, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "hyok-encrypted-data-keys" - ] - } - } + "properties": { + "is-overridable": { + "type": "boolean" } } }, - "outputs": { + "permissions": { "type": "object", "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "state-version-outputs" - ] - } - } - } - }, - "links": { - "$ref": "./related.yml" + "can-override": { + "type": "boolean" } } + } + } + }, + "relationships": { + "type": "object", + "properties": { + "run": { + "$ref": "#/components/schemas/runs-id" + } + } + }, + "links": { + "type": "object", + "properties": { + "output": { + "type": "string", + "nullable": true, + "description": "URL to download the policy check output log." }, - "links": null - }, - "$ref": "#/components/schemas/self" + "override": { + "type": "string", + "nullable": true, + "description": "URL to override a soft-failed policy check. Only present when the check is overridable." + } + } } } }, - "current-state-version-envelope": { + "policy-checks-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/state-versions" - }, - "included": { - "type": "array", - "items": { - "type": "object" - } + "$ref": "#/components/schemas/policy-checks" } } }, - "assessment-results": { + "tf-policy-evaluation": { "type": "object", + "description": "Represents a Terraform Policy evaluation for a run. Coordinates the evaluation of multiple policy sets and aggregates their results. Each evaluation is associated with a specific stage (Setup or Plan or Apply) in the run lifecycle.", "required": [ - "id", "type", "attributes" ], "properties": { "id": { "type": "string", - "example": "asmtres-8F5JFydVYAmtTjET" + "readOnly": true }, "type": { "type": "string", "enum": [ - "assessment-results" + "tf-policy-evaluations" ] }, "attributes": { "type": "object", "properties": { - "succeeded": { - "type": "boolean", - "description": "Whether the assessment completed successfully" - }, - "all-checks-succeeded": { - "type": "boolean", - "description": "Whether all health checks passed" - }, - "checks-errored": { - "type": "integer", - "description": "Number of health checks that errored", - "nullable": true - }, - "checks-failed": { - "type": "integer", - "description": "Number of health checks that failed", - "nullable": true + "status": { + "type": "string", + "description": "Current status of the Terraform policy evaluation. Status values:\n- `pending`: Initial state, not yet queued for evaluation\n- `queued`: Queued and waiting to be evaluated\n- `running`: Actively being evaluated\n- `awaiting_override`: Failed with overridable policies, awaiting manual override\n- `passed`: All policies passed (final state)\n- `failed`: Failed with mandatory policies (final state)\n- `overridden`: Failed evaluation manually overridden (final state)\n- `errored`: System error during processing (final state)\n- `canceled`: Canceled before completion (final state)\n- `unreachable`: Pseudo-state derived from run state\n", + "enum": [ + "pending", + "queued", + "running", + "awaiting_override", + "passed", + "failed", + "overridden", + "errored", + "canceled", + "unreachable" + ] }, - "checks-passed": { - "type": "integer", - "description": "Number of health checks that passed", - "nullable": true + "stage-type": { + "type": "string", + "description": "The type of stage this evaluation is associated with (e.g., 'Plan', 'Apply', 'Init')" }, - "checks-unknown": { - "type": "integer", - "description": "Number of health checks with unknown status", - "nullable": true + "status-timestamps": { + "type": "object", + "description": "Timestamps for each status transition during the evaluation lifecycle", + "properties": { + "pending-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the evaluation entered pending status" + }, + "queued-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the evaluation was queued for processing" + }, + "running-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the evaluation started running" + }, + "awaiting-override-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the evaluation entered awaiting override status (for failed mandatory policies)" + }, + "passed-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the evaluation passed successfully" + }, + "failed-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the evaluation failed" + }, + "overridden-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When a failed evaluation was overridden" + }, + "errored-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the evaluation encountered an error" + }, + "canceled-at": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "When the evaluation was canceled" + } + } }, "created-at": { "type": "string", "format": "date-time", - "description": "Timestamp when the assessment result was created" - }, - "drifted": { - "type": "boolean", - "description": "Whether drift was detected" + "readOnly": true, + "description": "When the evaluation was created" }, - "error-message": { + "updated-at": { "type": "string", - "nullable": true, - "description": "Error message if the assessment failed" + "format": "date-time", + "readOnly": true, + "description": "When the evaluation was last updated" }, - "resources-drifted": { - "type": "integer", - "nullable": true, - "description": "Number of resources that have drifted" + "result-count": { + "type": "object", + "description": "Aggregated counts of policy results across all policy sets in this evaluation", + "properties": { + "advisory-failed": { + "type": "integer", + "description": "Total number of policies with advisory enforcement level that failed across all policy sets" + }, + "mandatory-failed": { + "type": "integer", + "description": "Total number of policies with mandatory or mandatory-overridable enforcement level that failed across all policy sets" + }, + "passed": { + "type": "integer", + "description": "Total number of policies that passed across all policy sets" + }, + "errored": { + "type": "integer", + "description": "Total number of policies that encountered errors during evaluation across all policy sets" + }, + "unknown": { + "type": "integer", + "description": "Total number of policies with unknown evaluation results across all policy sets" + } + } }, - "resources-undrifted": { - "type": "integer", + "error": { + "type": "object", "nullable": true, - "description": "Number of resources that have not drifted" + "description": "Error information if the entire evaluation failed (not policy-specific errors)", + "properties": { + "type": { + "type": "string", + "enum": [ + "setup_error", + "incompatible_agent_version" + ], + "description": "Error type identifier indicating the category of failure" + }, + "summary": { + "type": "string", + "description": "Brief error summary for display" + }, + "detail": { + "type": "string", + "description": "Detailed error message with additional context" + } + } + }, + "organized-log": { + "type": "boolean", + "deprecated": true, + "description": "Deprecated. Always `true`." + }, + "permissions": { + "type": "object", + "description": "User permissions for this evaluation", + "properties": { + "can-override": { + "type": "boolean", + "description": "Whether the current user has permission to override failed policies" + } + } + }, + "actions": { + "type": "object", + "description": "Available actions for this evaluation", + "properties": { + "is-overridable": { + "type": "boolean", + "description": "Whether this evaluation can be overridden (based on policy enforcement levels and current status)" + } + } } } }, "relationships": { "type": "object", "properties": { - "workspace": { + "run": { "type": "object", - "description": "The workspace this assessment result belongs to", + "description": "The run that this policy evaluation belongs to", "properties": { "data": { "type": "object", - "required": [ - "id", - "type" - ], "properties": { "id": { - "type": "string" + "type": "string", + "description": "The run's external ID" }, "type": { "type": "string", - "enum": [ - "workspaces" - ] + "enum": [ + "runs" + ] + } + } + } + } + }, + "tf-policy-set-outcomes": { + "type": "object", + "description": "The Terraform policy set outcomes that are part of this evaluation", + "properties": { + "data": { + "type": "array", + "description": "List of Terraform policy set outcome resource identifiers", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The Terraform policy set outcome's external ID" + }, + "type": { + "type": "string", + "enum": [ + "tf-policy-set-outcomes" + ] + } + } + } + }, + "links": { + "type": "object", + "properties": { + "related": { + "type": "string", + "description": "URL to fetch the related Terraform policy set outcomes" } } } @@ -22796,183 +30098,280 @@ "type": "object", "properties": { "self": { - "type": "string", - "description": "API URL for this assessment result" - }, - "json-output": { - "type": "string", - "nullable": true, - "description": "API URL for the JSON formatted assessment output (available when assessment succeeded)" - }, - "json-schema": { - "type": "string", - "nullable": true, - "description": "API URL for the JSON schema of this assessment (available when assessment succeeded)" - }, - "sanitized-plan": { - "type": "string", - "nullable": true, - "description": "API URL for the sanitized plan (available when HYOK is enabled and assessment succeeded)", - "x-vis": [ - "public-beta" - ] - }, - "log-output": { - "type": "string", - "description": "API URL to read the logs for this assessment" + "type": "string" } } } } }, - "assessment-results-envelope": { + "tf-policy-evaluations-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/assessment-results" + "$ref": "#/components/schemas/tf-policy-evaluation" } } }, - "applies-id": { + "tf-policy-set-outcome": { "type": "object", + "description": "Represents the outcome of evaluating a Terraform Policy set against resources in a run. Contains detailed diagnostics organized by policy and enforce block, including information about resources that passed or failed policy evaluation.", + "required": [ + "type", + "attributes" + ], "properties": { - "data": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "applies" - ] - } - } + "id": { + "type": "string", + "readOnly": true }, - "links": { - "$ref": "#/components/schemas/related" - } - } - }, - "cost-estimates-id": { - "type": "object", - "properties": { - "data": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "cost-estimates" - ] - } - } + "type": { + "type": "string", + "enum": [ + "tf-policy-set-outcomes" + ] }, - "links": { - "$ref": "#/components/schemas/related" - } - } - }, - "plans-id": { - "type": "object", - "properties": { - "data": { + "attributes": { "type": "object", "properties": { - "id": { - "type": "string" + "outcomes": { + "type": "array", + "nullable": true, + "description": "List of policy outcomes, each representing the evaluation result of a single policy within the policy set", + "items": { + "type": "object", + "properties": { + "policy_name": { + "type": "string", + "description": "The name of the policy" + }, + "description": { + "type": "string", + "description": "The description of the policy" + }, + "file_name": { + "type": "string", + "description": "The filename of the policy" + }, + "enforcement_level": { + "type": "string", + "enum": [ + "advisory", + "mandatory", + "mandatory_overridable" + ], + "description": "The enforcement level of the policy" + }, + "status": { + "type": "string", + "enum": [ + "passed", + "failed", + "errored", + "unknown" + ], + "description": "The evaluation status of the policy" + }, + "diagnostics": { + "type": "array", + "nullable": true, + "description": "List of diagnostic entries grouped by enforce block", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "Code snippet from the policy file showing the enforce block that was evaluated" + }, + "context": { + "type": "string", + "nullable": true, + "description": "The policy declaration context (e.g., 'resource_policy \"aws_s3_bucket\" \"test\"')" + }, + "start_line": { + "type": "integer", + "nullable": true, + "description": "Line number where the enforce block starts in the policy file" + }, + "summary": { + "type": "string", + "description": "Human-readable summary of the diagnostic, typically the policy declaration" + }, + "error_message": { + "type": "string", + "nullable": true, + "description": "Error message for the enforce block when not specific to a resource" + }, + "resources": { + "type": "array", + "nullable": true, + "description": "List of Terraform resources that failed this enforce block's condition", + "items": { + "type": "object", + "properties": { + "resource_name": { + "type": "string", + "description": "The Terraform resource address (e.g., 'aws_s3_bucket.example')" + }, + "error_message": { + "type": "string", + "nullable": true, + "description": "Specific error message explaining why this resource failed the policy check" + }, + "info_message": { + "type": "string", + "nullable": true, + "description": "Policy-provided informational log message for debugging about this resource's evaluation" + }, + "file_name": { + "type": "string", + "nullable": true, + "description": "Terraform configuration file containing this resource (e.g., 'main.tf')" + }, + "code": { + "type": "string", + "nullable": true, + "description": "Code snippet from the Terraform configuration showing the resource declaration" + }, + "start_line": { + "type": "integer", + "nullable": true, + "description": "Line number where the resource is defined in the Terraform configuration file" + }, + "values": { + "type": "array", + "nullable": true, + "description": "List of attribute evaluations showing the actual values that caused the policy failure", + "items": { + "type": "object", + "properties": { + "traversal": { + "type": "string", + "description": "The attribute path that was evaluated" + }, + "statement": { + "type": "string", + "description": "The actual value of the attribute that was evaluated" + } + } + } + } + } + } + } + } + } + }, + "passed_resources": { + "type": "array", + "nullable": true, + "description": "List of Terraform resources that passed all enforce blocks in this policy", + "items": { + "type": "object", + "properties": { + "resource_name": { + "type": "string", + "description": "The Terraform resource address (e.g., 'aws_s3_bucket.compliant')" + }, + "info_messages": { + "type": "array", + "nullable": true, + "description": "List of informational messages from enforce blocks that this resource passed", + "items": { + "type": "string" + } + } + } + } + } + } + } }, - "type": { + "overridable": { + "type": "boolean", + "description": "Indicates if the policy set outcome can be overridden when policies fail" + }, + "policy-set-name": { "type": "string", - "enum": [ - "plans" - ] - } - } - }, - "links": { - "$ref": "#/components/schemas/related" - } - } - }, - "run-events-id": { - "type": "object", - "properties": { - "data": { - "type": "object", - "properties": { - "id": { - "type": "string" + "description": "Name of the policy set that was evaluated" }, - "type": { + "policy-set-description": { "type": "string", - "enum": [ - "run-events" - ] + "nullable": true, + "description": "Optional description of the policy set" + }, + "result-count": { + "type": "object", + "properties": { + "advisory-failed": { + "type": "integer", + "description": "Number of policies with advisory enforcement level that failed" + }, + "mandatory-failed": { + "type": "integer", + "description": "Number of policies with mandatory or mandatory-overridable enforcement level that failed" + }, + "passed": { + "type": "integer", + "description": "Number of policies that passed" + }, + "errored": { + "type": "integer", + "description": "Number of policies that encountered errors during evaluation" + }, + "unknown": { + "type": "integer", + "description": "Number of policies with unknown evaluation results (e.g., due to unknown Terraform values)" + } + } } } }, - "links": { - "$ref": "#/components/schemas/related" - } - } - }, - "task-stages-id": { - "type": "object", - "properties": { - "data": { + "relationships": { "type": "object", "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "task-stages" - ] + "tf-policy-evaluation": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "tf-policy-evaluations" + ] + } + } + } + } } } - }, - "links": { - "$ref": "#/components/schemas/related" } } }, - "policy-checks-id": { + "tf-policy-set-outcomes-envelope": { "type": "object", + "required": [ + "data" + ], "properties": { "data": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "policy-checks" - ] - } - } - }, - "links": { - "$ref": "#/components/schemas/related" + "$ref": "#/components/schemas/tf-policy-set-outcome" } } }, - "comments-id": { + "policy-set-versions-id": { "type": "object", "properties": { "data": { "type": "object", + "nullable": true, "properties": { "id": { "type": "string" @@ -22980,7 +30379,7 @@ "type": { "type": "string", "enum": [ - "workspace-comments" + "policy-set-versions" ] } } @@ -22990,341 +30389,187 @@ } } }, - "runs": { + "policies-id": { "type": "object", - "required": [ - "type", - "attributes" - ], "properties": { - "id": { - "type": "string", - "readOnly": true - }, - "type": { - "type": "string", - "enum": [ - "runs" - ] - }, - "attributes": { + "data": { "type": "object", "properties": { - "actions": { - "type": "object", - "properties": { - "is-cancelable": { - "type": "boolean" - }, - "is-confirmable": { - "type": "boolean" - }, - "is-discardable": { - "type": "boolean" - }, - "is-force-cancelable": { - "type": "boolean" - } - } - }, - "allow-config-generation": { - "type": "boolean" - }, - "allow-empty-apply": { - "type": "boolean" - }, - "auto-apply": { - "type": "boolean" - }, - "comment": { - "type": "string", - "writeOnly": true - }, - "canceled-at": { - "type": "string", - "format": "date-time", - "nullable": true, - "readOnly": true - }, - "created-at": { - "type": "string", - "format": "date-time", - "readOnly": true - }, - "debugging-mode": { - "type": "boolean" - }, - "has-changes": { - "type": "boolean" - }, - "is-destroy": { - "type": "boolean" - }, - "message": { - "type": "string" - }, - "plan-only": { - "type": "boolean" - }, - "refresh": { - "type": "boolean" - }, - "refresh-only": { - "type": "boolean" - }, - "replace-addrs": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "save-plan": { - "type": "boolean" - }, - "source": { + "id": { "type": "string" - }, - "status-timestamps": { - "type": "object", - "properties": { - "fetching-at": { - "type": "string", - "format": "date-time" - }, - "fetched-at": { - "type": "string", - "format": "date-time" - }, - "pre-plan-running-at": { - "type": "string", - "format": "date-time" - }, - "pre-plan-completed-at": { - "type": "string", - "format": "date-time" - }, - "plan-queued-at": { - "type": "string", - "format": "date-time" - }, - "planning-at": { - "type": "string", - "format": "date-time" - }, - "planned-at": { - "type": "string", - "format": "date-time" - }, - "post-plan-running-at": { - "type": "string", - "format": "date-time" - }, - "post-plan-completed-at": { - "type": "string", - "format": "date-time" - }, - "cost-estimating-at": { - "type": "string", - "format": "date-time" - }, - "cost-estimated-at": { - "type": "string", - "format": "date-time" - }, - "policy-soft-failed-at": { - "type": "string", - "format": "date-time" - }, - "policy-checked-at": { - "type": "string", - "format": "date-time" - }, - "confirmed-at": { - "type": "string", - "format": "date-time" - }, - "planned-and-finished-at": { - "type": "string", - "format": "date-time" - }, - "planned-and-saved-at": { - "type": "string", - "format": "date-time" - }, - "pre-apply-running-at": { - "type": "string", - "format": "date-time" - }, - "pre-apply-completed-at": { - "type": "string", - "format": "date-time" - }, - "apply-queued-at": { - "type": "string", - "format": "date-time" - }, - "applying-at": { - "type": "string", - "format": "date-time" - }, - "post-apply-completed-at": { - "type": "string", - "format": "date-time" - }, - "applied-at": { - "type": "string", - "format": "date-time" - }, - "post-apply-running-at": { - "type": "string", - "format": "date-time" - }, - "discarded-at": { - "type": "string", - "format": "date-time" - }, - "errored-at": { - "type": "string", - "format": "date-time" - }, - "canceled-at": { - "type": "string", - "format": "date-time" - }, - "force-canceled-at": { - "type": "string", - "format": "date-time" - }, - "assessed-at": { - "type": "string", - "format": "date-time" - }, - "queuing-at": { - "type": "string", - "format": "date-time" - }, - "queuing-apply-at": { - "type": "string", - "format": "date-time" - } - } - }, - "status": { - "type": "string", - "enum": [ - "pending", - "fetching", - "fetching_completed", - "pre_plan_running", - "pre_plan_completed", - "queuing", - "plan_queued", - "planning", - "planned", - "post_plan_running", - "post_plan_completed", - "cost_estimating", - "cost_estimated", - "policy_checking", - "policy_override", - "policy_soft_failed", - "policy_checked", - "confirmed", - "pre_apply_running", - "pre_apply_completed", - "queuing_apply", - "apply_queued", - "applying", - "post_apply_running", - "post_apply_completed", - "applied", - "discarded", - "errored", - "canceled", - "planned_and_finished", - "planned_and_saved", - "assessing", - "assessed" + }, + "type": { + "type": "string", + "enum": [ + "policies" ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "policy-sets": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "policy-sets" + ] + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string" }, - "target-addrs": { - "type": "array", - "items": { - "type": "string" - }, + "description": { + "type": "string", "nullable": true }, - "trigger-reason": { - "type": "string" + "global": { + "type": "boolean" }, - "terraform-version": { - "type": "string" + "workspace-count": { + "type": "integer", + "readOnly": true }, - "updated-at": { - "type": "string", - "format": "date-time", + "project-count": { + "type": "integer", "readOnly": true }, - "triggering-source-name": { + "versioned": { + "type": "boolean", + "readOnly": true + }, + "kind": { + "type": "string", + "description": "The kind of policies contained in this policy set.\n\n**Note:** The following kind values are in public-beta:\n- `tfpolicy` - Terraform Policy enforcement\n", + "enum": [ + "sentinel", + "opa", + "tfpolicy" + ] + }, + "agent-enabled": { + "type": "boolean" + }, + "policy-tool-version": { "type": "string", "nullable": true }, - "policy-paths": { - "type": "array", - "items": { - "type": "string" - }, + "overridable": { + "type": "boolean", "nullable": true }, - "invoke-action-addrs": { - "type": "array", - "items": { - "type": "string" - }, + "policy-count": { + "type": "integer", + "readOnly": true + }, + "policies-path": { + "type": "string", "nullable": true }, - "permissions": { + "vcs-repo": { "type": "object", + "nullable": true, "properties": { - "can-apply": { - "type": "boolean" + "branch": { + "type": "string", + "nullable": true }, - "can-cancel": { - "type": "boolean" + "identifier": { + "type": "string" }, - "can-comment": { - "type": "boolean" + "display-identifier": { + "type": "string", + "nullable": true }, - "can-discard": { - "type": "boolean" + "oauth-token-id": { + "type": "string", + "nullable": true }, - "can-force-execute": { - "type": "boolean" + "github-app-installation-id": { + "type": "string", + "nullable": true }, - "can-force-cancel": { + "ingress-submodules": { "type": "boolean" }, - "can-override-policy-check": { - "type": "boolean" + "webhook-url": { + "type": "string", + "nullable": true + }, + "repository-http-url": { + "type": "string", + "nullable": true + }, + "service-provider": { + "type": "string", + "nullable": true } } }, - "variables": { + "policy-update-patterns": { + "type": "array", + "items": { + "type": "string" + } + }, + "tag-selectors": { "type": "array", + "x-vis": [ + "public-beta" + ], "items": { "type": "object", + "required": [ + "tag-key", + "tag-value", + "is-exclude" + ], "properties": { - "key": { + "tag-key": { "type": "string" }, - "value": { - "type": "string" + "tag-value": { + "type": "string", + "nullable": true + }, + "is-exclude": { + "type": "boolean" } } - } + }, + "description": "This attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users." }, - "force-cancel-available-at": { + "scoping-type": { + "type": "string", + "x-vis": [ + "public-beta" + ], + "description": "Scoping mode for the policy set. \"tag\" is dynamic tag-based scoping. \"explicit\" uses explicit workspace/project associations.\n\nThis attribute is considered BETA, is SUBJECT TO CHANGE, and may be unavailable to some users.", + "enum": [ + "tag", + "explicit" + ] + }, + "created-at": { + "type": "string", + "format": "date-time", + "readOnly": true + }, + "updated-at": { "type": "string", "format": "date-time", "readOnly": true @@ -23334,122 +30579,123 @@ "relationships": { "type": "object", "properties": { - "workspace": { - "$ref": "#/components/schemas/workspaces-id" - }, - "triggering-source": { - "$ref": "#/components/schemas/workspaces-id" - }, - "triggering-run": { - "$ref": "#/components/schemas/runs-id" - }, - "apply": { - "$ref": "#/components/schemas/applies-id" - }, - "canceled-by": { - "$ref": "#/components/schemas/users-id" - }, - "configuration-version": { - "$ref": "#/components/schemas/configuration-versions-id" - }, - "confirmed-by": { - "$ref": "#/components/schemas/users-id" - }, - "cost-estimate": { - "$ref": "#/components/schemas/cost-estimates-id" + "organization": { + "$ref": "#/components/schemas/organizations-id" }, - "created-by": { - "$ref": "#/components/schemas/users-id" + "current-version": { + "$ref": "#/components/schemas/policy-set-versions-id" }, - "plan": { - "$ref": "#/components/schemas/plans-id" + "newest-version": { + "$ref": "#/components/schemas/policy-set-versions-id" }, - "run-events": { + "policies": { "type": "object", "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/run-events-id" + "$ref": "#/components/schemas/policies-id" } } } }, - "task-stages": { + "workspaces": { "type": "object", "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/task-stages-id" + "$ref": "#/components/schemas/workspaces-id" } } } }, - "policy-checks": { + "projects": { "type": "object", "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/policy-checks-id" + "$ref": "#/components/schemas/projects-id" } } } }, - "run-trigger-snapshots": { - "$ref": "#/components/schemas/related" + "workspace-exclusions": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/workspaces-id" + } + } + } }, - "comments": { + "project-exclusions": { "type": "object", "properties": { "data": { "type": "array", "items": { - "$ref": "#/components/schemas/comments-id" + "$ref": "#/components/schemas/projects-id" } } } } } + }, + "links": { + "type": "object", + "properties": { + "self": { + "type": "string" + } + } } } }, - "runs-envelope": { + "policy-sets-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/runs" + "$ref": "#/components/schemas/policy-sets" } } }, - "ingress-attributes-id": { - "type": "object", - "properties": { - "data": { - "nullable": true, - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "ingress-attributes" - ] + "policies-identifier-array-document": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "required": [ + "type", + "id" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "policies" + ] + }, + "id": { + "type": "string" + } } } - }, - "links": { - "$ref": "#/components/schemas/related" } } }, - "configuration-versions": { + "policy-set-versions": { "type": "object", "required": [ "type", @@ -23463,88 +30709,86 @@ "type": { "type": "string", "enum": [ - "configuration-versions" + "policy-set-versions" ] }, "attributes": { "type": "object", "properties": { - "auto-queue-runs": { - "type": "boolean" - }, - "error": { - "type": "string", - "nullable": true - }, - "error-message": { - "type": "string", - "nullable": true - }, "source": { "type": "string", "nullable": true }, - "speculative": { - "type": "boolean" - }, "status": { "type": "string", "enum": [ "pending", - "fetching", - "uploaded", - "archived", + "ingressing", + "ready", "errored", - "backing_data_soft_deleted", - "backing_data_permanently_deleted" + "canceled" ] }, "status-timestamps": { "type": "object", + "nullable": true, "properties": { - "fetching-at": { + "pending-at": { "type": "string", - "format": "date-time", - "nullable": true + "format": "date-time" }, - "uploaded-at": { + "ingressing-at": { "type": "string", - "format": "date-time", - "nullable": true + "format": "date-time" }, - "errored-at": { + "ready-at": { "type": "string", - "format": "date-time", - "nullable": true + "format": "date-time" }, - "archived-at": { + "errored-at": { "type": "string", - "format": "date-time", - "nullable": true + "format": "date-time" }, - "soft-delete-backing-data-at": { + "canceled-at": { + "type": "string", + "format": "date-time" + } + } + }, + "error": { + "type": "string", + "nullable": true + }, + "error-message": { + "type": "string", + "nullable": true + }, + "ingress-attributes": { + "type": "object", + "nullable": true, + "properties": { + "commit-sha": { "type": "string", - "format": "date-time", "nullable": true }, - "restore-backing-data-at": { + "commit-url": { "type": "string", - "format": "date-time", "nullable": true }, - "permanently-delete-backing-data-at": { + "identifier": { "type": "string", - "format": "date-time", "nullable": true } } }, - "provisional": { - "type": "boolean" + "created-at": { + "type": "string", + "format": "date-time", + "readOnly": true }, - "upload-url": { + "updated-at": { "type": "string", - "nullable": true, + "format": "date-time", "readOnly": true } } @@ -23552,8 +30796,8 @@ "relationships": { "type": "object", "properties": { - "ingress-attributes": { - "$ref": "#/components/schemas/ingress-attributes-id" + "policy-set": { + "$ref": "#/components/schemas/policy-sets-id" } } }, @@ -23563,325 +30807,135 @@ "self": { "type": "string" }, - "download": { - "type": "string" - } - } - } - } - }, - "configuration-versions-envelope": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "$ref": "#/components/schemas/configuration-versions" - } - } - }, - "comments": { - "type": "object", - "required": [ - "type", - "attributes" - ], - "properties": { - "id": { - "type": "string", - "readOnly": true - }, - "type": { - "type": "string", - "enum": [ - "comments" - ] - }, - "attributes": { - "type": "object", - "properties": { - "body": { - "type": "string" - } - } - }, - "relationships": { - "type": "object", - "properties": { - "run-event": { - "$ref": "#/components/schemas/run-events-id" - } - } - } - } - }, - "comments-envelope": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "$ref": "#/components/schemas/comments" - } - } - }, - "action-comment": { - "type": "object", - "properties": { - "comment": { - "type": "string", - "nullable": true - } - } - }, - "run-triggers": { - "type": "object", - "required": [ - "type", - "attributes" - ], - "properties": { - "id": { - "type": "string", - "readOnly": true - }, - "type": { - "type": "string", - "enum": [ - "run-triggers" - ] - }, - "attributes": { - "type": "object", - "properties": { - "workspace-name": { - "type": "string" - }, - "sourceable-name": { - "type": "string" - }, - "created-at": { + "upload": { "type": "string", - "format": "date-time", - "readOnly": true - } - } - }, - "relationships": { - "type": "object", - "properties": { - "workspace": { - "$ref": "#/components/schemas/workspaces-id" - }, - "sourceable": { - "$ref": "#/components/schemas/workspaces-id" + "nullable": true } } - }, - "links": { - "$ref": "#/components/schemas/self" } } }, - "run-triggers-envelope": { + "policy-set-versions-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/run-triggers" - } - } - }, - "pagination-without-totals": { - "type": "object", - "properties": { - "current-page": { - "type": "integer" - }, - "page-size": { - "type": "integer" - }, - "prev-page": { - "type": "integer", - "nullable": true - }, - "next-page": { - "type": "integer", - "nullable": true + "$ref": "#/components/schemas/policy-set-versions" } } }, - "plans": { + "policy-evaluations": { "type": "object", "required": [ - "id", "type", "attributes" ], "properties": { "id": { "type": "string", - "example": "plan-8F5JFydVYAmtTjET" + "readOnly": true }, "type": { "type": "string", "enum": [ - "plans" + "policy-evaluations" ] }, "attributes": { "type": "object", "properties": { - "execution-details": { - "type": "object", - "nullable": true, - "description": "Details about the execution of this plan. Null if plan has not started.", - "properties": { - "mode": { - "type": "string", - "description": "Execution mode of the run", - "enum": [ - "remote", - "agent", - "local" - ] - }, - "agent-id": { - "type": "string", - "example": "agent-S1Y7tcKxXPJDQAvq", - "description": "ID of the agent used for this run (when mode is agent)", - "x-vis": [ - "hcpt" - ] - }, - "agent-name": { - "type": "string", - "example": "agent_01", - "description": "Name of the agent used for this run (when mode is agent)", - "x-vis": [ - "hcpt" - ] - }, - "agent-pool-id": { - "type": "string", - "example": "apool-Zigq2VGreKq7nwph", - "description": "ID of the agent pool used for this run (when mode is agent)", - "x-vis": [ - "hcpt" - ] - }, - "agent-pool-name": { - "type": "string", - "example": "first-pool", - "description": "Name of the agent pool used for this run (when mode is agent)", - "x-vis": [ - "hcpt" - ] - } - } - }, - "generated-configuration": { - "type": "boolean", - "default": false, - "nullable": true, - "description": "Whether the plan generated new configuration as part of this run" - }, - "has-changes": { - "type": "boolean", - "description": "Whether the plan has any changes" - }, - "resource-additions": { - "type": "integer", - "description": "Number of resources that will be added", - "nullable": true - }, - "resource-changes": { - "type": "integer", - "description": "Number of resources that will be changed", - "nullable": true - }, - "resource-destructions": { - "type": "integer", - "description": "Number of resources that will be destroyed", - "nullable": true - }, - "resource-imports": { - "type": "integer", - "description": "Number of resources that will be imported", - "nullable": true - }, - "structured-run-output-enabled": { - "type": "boolean", - "nullable": true, - "description": "Whether structured run output is enabled" - }, "status": { "type": "string", - "description": "Current status of the plan", "enum": [ "pending", - "managed_queued", "queued", "running", + "passed", + "failed", + "overridden", "errored", "canceled", - "finished", "unreachable" ] }, + "policy-kind": { + "type": "string", + "enum": [ + "sentinel", + "opa" + ] + }, "status-timestamps": { "type": "object", - "description": "Timestamps for state transitions of the plan", "properties": { + "pending-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, "queued-at": { "type": "string", "format": "date-time", "nullable": true }, - "pending-at": { + "running-at": { "type": "string", "format": "date-time", "nullable": true }, - "started-at": { + "passed-at": { "type": "string", "format": "date-time", "nullable": true }, - "finished-at": { + "failed-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "overridden-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "errored-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "canceled-at": { "type": "string", "format": "date-time", "nullable": true } } }, - "log-read-url": { + "created-at": { "type": "string", - "nullable": true, - "description": "URL to read the logs for this plan" + "format": "date-time", + "readOnly": true }, - "actions": { - "type": "object", - "description": "Actions available for this plan", - "properties": { - "is-exportable": { - "type": "boolean", - "description": "Whether the plan can be exported" - } - } + "updated-at": { + "type": "string", + "format": "date-time", + "readOnly": true }, - "permissions": { + "result-count": { "type": "object", - "description": "Permissions for the current user related to this plan", - "nullable": true, "properties": { - "can-export": { - "type": "boolean", - "description": "Whether the current user can export the plan" + "advisory-failed": { + "type": "integer" + }, + "mandatory-failed": { + "type": "integer" + }, + "passed": { + "type": "integer" + }, + "errored": { + "type": "integer" } } } @@ -23890,45 +30944,32 @@ "relationships": { "type": "object", "properties": { - "state-versions": { + "policy-attachable": { "type": "object", - "description": "State versions associated with this plan (for TF <= 0.8)", "properties": { "data": { - "type": "array", - "items": { - "type": "object", - "required": [ - "id", - "type" - ], - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "state-versions" - ] - } + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "task-stages" + ] } } } } }, - "exports": { + "policy-set-outcomes": { "type": "object", - "description": "Exports associated with this plan", "properties": { "data": { "type": "array", "items": { "type": "object", - "required": [ - "id", - "type" - ], "properties": { "id": { "type": "string" @@ -23936,38 +30977,17 @@ "type": { "type": "string", "enum": [ - "plan-exports" + "policy-set-outcomes" ] } } } - } - } - }, - "hyok-encrypted-data-key": { - "type": "object", - "description": "HYOK encrypted data key associated with this plan", - "nullable": true, - "x-vis": [ - "public-beta" - ], - "properties": { - "data": { + }, + "links": { "type": "object", - "nullable": true, - "required": [ - "id", - "type" - ], "properties": { - "id": { + "related": { "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "hyok-encrypted-data-keys" - ] } } } @@ -23975,52 +30995,28 @@ } } }, - "links": { - "type": "object", - "properties": { - "self": { - "type": "string", - "description": "API URL for this plan" - }, - "json-output": { - "type": "string", - "nullable": true, - "description": "API URL for the JSON formatted execution plan (available for Terraform 0.12+)" - }, - "json-output-redacted": { - "type": "string", - "nullable": true, - "description": "API URL for the redacted JSON formatted execution plan (available for Terraform 0.15.2+)" - }, - "json-schema": { - "type": "string", - "nullable": true, - "description": "API URL for the JSON schema of this plan (available for Terraform 0.12+)" - }, - "sanitized-plan": { - "type": "string", - "nullable": true, - "description": "API URL for the sanitized plan (available when HYOK is enabled and with compatible Terraform version)", - "x-vis": [ - "public-beta" - ] + "links": { + "type": "object", + "properties": { + "self": { + "type": "string" } } } } }, - "plans-envelope": { + "policy-evaluations-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/plans" + "$ref": "#/components/schemas/policy-evaluations" } } }, - "policy-sets-id": { + "policy-evaluations-id": { "type": "object", "properties": { "data": { @@ -24032,7 +31028,7 @@ "type": { "type": "string", "enum": [ - "policy-sets" + "policy-evaluations" ] } } @@ -24042,10 +31038,11 @@ } } }, - "policies": { + "policy-set-outcomes": { "type": "object", "required": [ - "type" + "type", + "attributes" ], "properties": { "id": { @@ -24055,319 +31052,112 @@ "type": { "type": "string", "enum": [ - "policies" + "policy-set-outcomes" ] }, "attributes": { "type": "object", "properties": { - "name": { - "type": "string", - "description": "The name of the policy." - }, - "description": { - "type": "string", - "nullable": true, - "description": "Text describing the policy's purpose. Supports Markdown." - }, - "kind": { - "type": "string", - "enum": [ - "sentinel", - "opa" - ], - "description": "The policy-as-code framework for the policy." - }, - "query": { - "type": "string", - "nullable": true, - "description": "The OPA query to run. Only present for OPA policies." - }, - "enforcement-level": { - "type": "string", - "enum": [ - "hard-mandatory", - "soft-mandatory", - "advisory", - "mandatory" - ], - "description": "The enforcement level of the policy. For Sentinel, valid values are hard-mandatory, soft-mandatory, and advisory. For OPA, valid values are mandatory and advisory." - }, - "enforce": { + "outcomes": { "type": "array", - "description": "DEPRECATED: Use enforcement-level instead. An array of enforcement configurations mapping policy file paths to their enforcement modes.", + "nullable": true, "items": { "type": "object", "properties": { - "path": { + "enforcement_level": { + "type": "string", + "nullable": true + }, + "query": { + "type": "string", + "nullable": true + }, + "status": { "type": "string" }, - "mode": { + "policy_name": { + "type": "string", + "nullable": true + }, + "description": { "type": "string" + }, + "output": { + "type": "array", + "nullable": true, + "items": {} } } } }, - "policy-set-count": { - "type": "integer", - "readOnly": true, - "description": "The number of policy sets that include this policy." - }, - "updated-at": { + "error": { "type": "string", - "format": "date-time", - "nullable": true, - "readOnly": true, - "description": "The time of the most recent policy code upload." - } - } - }, - "relationships": { - "type": "object", - "properties": { - "organization": { - "$ref": "#/components/schemas/organizations-id" + "nullable": true }, - "policy-sets": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/policy-sets-id" - } - } - } - } - } - } - } - }, - "policies-envelope": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "$ref": "#/components/schemas/policies" - } - } - }, - "policy-checks": { - "type": "object", - "required": [ - "type", - "attributes" - ], - "properties": { - "id": { - "type": "string", - "readOnly": true - }, - "type": { - "type": "string", - "enum": [ - "policy-checks" - ] - }, - "attributes": { - "type": "object", - "properties": { - "result": { - "type": "object", - "nullable": true, - "description": "The result of the policy evaluation. Null until the policy check completes. The `sentinel` key contains low-level Sentinel details and its structure may change over time.", - "properties": { - "result": { - "type": "boolean" - }, - "passed": { - "type": "integer" - }, - "total-failed": { - "type": "integer" - }, - "hard-failed": { - "type": "integer" - }, - "soft-failed": { - "type": "integer" - }, - "advisory-failed": { - "type": "integer" - }, - "duration-ms": { - "type": "integer" - }, - "sentinel": { - "type": "object", - "additionalProperties": true, - "nullable": true - } + "warnings": { + "type": "array", + "items": { + "type": "string" } }, - "scope": { - "type": "string", - "description": "The scope of policies evaluated in this check (e.g. \"organization\")." + "overridable": { + "type": "boolean" }, - "status": { + "policy-set-name": { + "type": "string" + }, + "policy-set-description": { "type": "string", - "enum": [ - "pending", - "queued", - "passed", - "soft_failed", - "hard_failed", - "overridden", - "errored", - "canceled", - "unreachable" - ] + "nullable": true }, - "status-timestamps": { + "result-count": { "type": "object", "properties": { - "queued-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "passed-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "soft-failed-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "hard-failed-at": { - "type": "string", - "format": "date-time", - "nullable": true + "advisory-failed": { + "type": "integer" }, - "overridden-at": { - "type": "string", - "format": "date-time", - "nullable": true + "mandatory-failed": { + "type": "integer" }, - "errored-at": { - "type": "string", - "format": "date-time", - "nullable": true + "passed": { + "type": "integer" }, - "canceled-at": { - "type": "string", - "format": "date-time", - "nullable": true - } - } - }, - "actions": { - "type": "object", - "properties": { - "is-overridable": { - "type": "boolean" - } - } - }, - "permissions": { - "type": "object", - "properties": { - "can-override": { - "type": "boolean" + "errored": { + "type": "integer" } } + }, + "policy-tool-version": { + "type": "string" } } }, "relationships": { "type": "object", "properties": { - "run": { - "$ref": "#/components/schemas/runs-id" - } - } - }, - "links": { - "type": "object", - "properties": { - "output": { - "type": "string", - "nullable": true, - "description": "URL to download the policy check output log." - }, - "override": { - "type": "string", - "nullable": true, - "description": "URL to override a soft-failed policy check. Only present when the check is overridable." + "policy-evaluation": { + "$ref": "#/components/schemas/policy-evaluations-id" } } } } }, - "policy-checks-envelope": { + "policy-set-outcomes-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/policy-checks" - } - } - }, - "policy-set-versions-id": { - "type": "object", - "properties": { - "data": { - "type": "object", - "nullable": true, - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "policy-set-versions" - ] - } - } - }, - "links": { - "$ref": "#/components/schemas/related" - } - } - }, - "policies-id": { - "type": "object", - "properties": { - "data": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "policies" - ] - } - } - }, - "links": { - "$ref": "#/components/schemas/related" + "$ref": "#/components/schemas/policy-set-outcomes" } } }, - "policy-sets": { + "plan-exports": { "type": "object", "required": [ - "type" + "type", + "attributes" ], "properties": { "id": { @@ -24377,196 +31167,75 @@ "type": { "type": "string", "enum": [ - "policy-sets" + "plan-exports" ] }, "attributes": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "global": { - "type": "boolean" - }, - "workspace-count": { - "type": "integer", - "readOnly": true - }, - "project-count": { - "type": "integer", - "readOnly": true - }, - "versioned": { - "type": "boolean", - "readOnly": true - }, - "kind": { + "data-type": { "type": "string", "enum": [ - "sentinel", - "opa", - "tfpolicy" + "sentinel-mock-bundle-v0" ] }, - "agent-enabled": { - "type": "boolean" - }, - "policy-tool-version": { - "type": "string", - "nullable": true - }, - "overridable": { - "type": "boolean", - "nullable": true - }, - "policy-count": { - "type": "integer", - "readOnly": true - }, - "policies-path": { + "status": { "type": "string", - "nullable": true + "enum": [ + "pending", + "queued", + "finished", + "expired", + "canceled", + "errored" + ] }, - "vcs-repo": { + "status-timestamps": { "type": "object", - "nullable": true, "properties": { - "branch": { - "type": "string", - "nullable": true - }, - "identifier": { - "type": "string" - }, - "display-identifier": { + "pending-at": { "type": "string", + "format": "date-time", "nullable": true }, - "oauth-token-id": { + "queued-at": { "type": "string", + "format": "date-time", "nullable": true }, - "github-app-installation-id": { + "finished-at": { "type": "string", + "format": "date-time", "nullable": true }, - "ingress-submodules": { - "type": "boolean" - }, - "webhook-url": { + "expired-at": { "type": "string", + "format": "date-time", "nullable": true }, - "repository-http-url": { + "canceled-at": { "type": "string", + "format": "date-time", "nullable": true }, - "service-provider": { + "errored-at": { "type": "string", + "format": "date-time", "nullable": true } } }, - "policy-update-patterns": { - "type": "array", - "items": { - "type": "string" - } - }, - "evaluation-stages": { - "type": "array", - "nullable": true, - "items": { - "type": "string" - } - }, - "enforcement-level": { + "error-message": { "type": "string", "nullable": true - }, - "created-at": { - "type": "string", - "format": "date-time", - "readOnly": true - }, - "updated-at": { - "type": "string", - "format": "date-time", - "readOnly": true } - } - }, - "relationships": { - "type": "object", - "properties": { - "organization": { - "$ref": "#/components/schemas/organizations-id" - }, - "current-version": { - "$ref": "#/components/schemas/policy-set-versions-id" - }, - "newest-version": { - "$ref": "#/components/schemas/policy-set-versions-id" - }, - "policies": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/policies-id" - } - } - } - }, - "workspaces": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/workspaces-id" - } - } - } - }, - "projects": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/projects-id" - } - } - } - }, - "workspace-exclusions": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/workspaces-id" - } - } - } - }, - "project-exclusions": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/projects-id" - } - } - } + } + }, + "relationships": { + "type": "object", + "properties": { + "plan": { + "$ref": "#/components/schemas/plans-id" } } }, @@ -24575,183 +31244,206 @@ "properties": { "self": { "type": "string" + }, + "download": { + "type": "string", + "nullable": true } } } } }, - "policy-sets-envelope": { + "plan-exports-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/policy-sets" + "$ref": "#/components/schemas/plan-exports" } } }, - "policies-identifier-array-document": { + "state-versions-id": { "type": "object", "required": [ - "data" + "id", + "type" ], "properties": { - "data": { - "type": "array", - "items": { - "type": "object", - "required": [ - "type", - "id" - ], - "properties": { - "type": { - "type": "string", - "enum": [ - "policies" - ] - }, - "id": { - "type": "string" - } - } - } + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "state-versions" + ] } } }, - "policy-set-versions": { + "applies": { "type": "object", - "required": [ - "type", - "attributes" - ], "properties": { "id": { - "type": "string", - "readOnly": true + "type": "string" }, "type": { "type": "string", "enum": [ - "policy-set-versions" + "applies" ] }, "attributes": { "type": "object", "properties": { - "source": { - "type": "string", - "nullable": true + "execution-details": { + "type": "object", + "readOnly": true, + "nullable": true, + "properties": { + "mode": { + "type": "string", + "enum": [ + "agent", + "remote", + "local" + ] + }, + "agent-id": { + "type": "string" + }, + "agent-name": { + "type": "string" + }, + "agent-pool-id": { + "type": "string" + }, + "agent-pool-name": { + "type": "string" + } + } }, "status": { + "readOnly": true, "type": "string", "enum": [ + "created", "pending", - "ingressing", - "ready", + "queued", + "agent_queued", + "running", "errored", - "canceled" + "canceled", + "finished", + "unreachable" ] }, "status-timestamps": { + "readOnly": true, "type": "object", - "nullable": true, "properties": { - "pending-at": { - "type": "string", - "format": "date-time" - }, - "ingressing-at": { + "agent-queued-at": { "type": "string", - "format": "date-time" + "format": "date-time", + "nullable": true }, - "ready-at": { + "started-at": { "type": "string", - "format": "date-time" + "format": "date-time", + "nullable": true }, "errored-at": { "type": "string", - "format": "date-time" + "format": "date-time", + "nullable": true }, "canceled-at": { "type": "string", - "format": "date-time" - } - } - }, - "error": { - "type": "string", - "nullable": true - }, - "error-message": { - "type": "string", - "nullable": true - }, - "ingress-attributes": { - "type": "object", - "nullable": true, - "properties": { - "commit-sha": { - "type": "string", + "format": "date-time", "nullable": true }, - "commit-url": { + "force-canceled-at": { "type": "string", + "format": "date-time", "nullable": true }, - "identifier": { + "finished-at": { "type": "string", + "format": "date-time", "nullable": true } } }, - "created-at": { - "type": "string", - "format": "date-time", - "readOnly": true + "log-read-url": { + "readOnly": true, + "type": "string" }, - "updated-at": { - "type": "string", - "format": "date-time", - "readOnly": true + "resource-additions": { + "readOnly": true, + "type": "integer", + "nullable": true + }, + "resource-changes": { + "readOnly": true, + "type": "integer", + "nullable": true + }, + "resource-destructions": { + "readOnly": true, + "type": "integer", + "nullable": true + }, + "resource-imports": { + "readOnly": true, + "type": "integer", + "nullable": true + }, + "action-invocations": { + "readOnly": true, + "type": "integer", + "nullable": true + }, + "action-failures": { + "readOnly": true, + "type": "integer", + "nullable": true } } }, "relationships": { "type": "object", "properties": { - "policy-set": { - "$ref": "#/components/schemas/policy-sets-id" + "state-versions": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/state-versions-id" + } + } + } } } }, "links": { - "type": "object", - "properties": { - "self": { - "type": "string" - }, - "upload": { - "type": "string", - "nullable": true - } - } + "$ref": "#/components/schemas/self" } } }, - "policy-set-versions-envelope": { + "applies-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/policy-set-versions" + "$ref": "#/components/schemas/applies" } } }, - "policy-evaluations": { + "cost-estimates": { "type": "object", "required": [ "type", @@ -24765,31 +31457,26 @@ "type": { "type": "string", "enum": [ - "policy-evaluations" + "cost-estimates" ] }, "attributes": { "type": "object", "properties": { + "error-message": { + "type": "string", + "nullable": true + }, "status": { "type": "string", "enum": [ "pending", "queued", - "running", - "passed", - "failed", - "overridden", - "errored", + "finished", "canceled", - "unreachable" - ] - }, - "policy-kind": { - "type": "string", - "enum": [ - "sentinel", - "opa" + "errored", + "unreachable", + "skipped_due_to_targeting" ] }, "status-timestamps": { @@ -24797,178 +31484,110 @@ "properties": { "pending-at": { "type": "string", - "format": "date-time", - "nullable": true + "format": "date-time" }, "queued-at": { "type": "string", - "format": "date-time", - "nullable": true - }, - "running-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "passed-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "failed-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "overridden-at": { - "type": "string", - "format": "date-time", - "nullable": true + "format": "date-time" }, - "errored-at": { + "finished-at": { "type": "string", - "format": "date-time", - "nullable": true + "format": "date-time" }, "canceled-at": { "type": "string", - "format": "date-time", - "nullable": true - } - } - }, - "created-at": { - "type": "string", - "format": "date-time", - "readOnly": true - }, - "updated-at": { - "type": "string", - "format": "date-time", - "readOnly": true - }, - "result-count": { - "type": "object", - "properties": { - "advisory-failed": { - "type": "integer" - }, - "mandatory-failed": { - "type": "integer" + "format": "date-time" }, - "passed": { - "type": "integer" + "errored-at": { + "type": "string", + "format": "date-time" }, - "errored": { - "type": "integer" - } - } - } - } - }, - "relationships": { - "type": "object", - "properties": { - "policy-attachable": { - "type": "object", - "properties": { - "data": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "task-stages" - ] - } - } + "skipped-due-to-targeting-at": { + "type": "string", + "format": "date-time" } } }, - "policy-set-outcomes": { + "resources": { "type": "object", + "nullable": true, + "description": "Low-level cost estimation details, only present when status is \"finished\". The keys or structure of this hash may change over time.", "properties": { - "data": { + "matched": { "type": "array", "items": { "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "policy-set-outcomes" - ] - } - } + "additionalProperties": true } }, - "links": { - "type": "object", - "properties": { - "related": { - "type": "string" - } + "unmatched": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": true } } } - } - } - }, - "links": { - "type": "object", - "properties": { - "self": { - "type": "string" + }, + "resources-count": { + "type": "integer", + "nullable": true, + "description": "Total number of resources. Only present when status is \"finished\"." + }, + "matched-resources-count": { + "type": "integer", + "nullable": true, + "description": "Number of matched resources. Only present when status is \"finished\"." + }, + "unmatched-resources-count": { + "type": "integer", + "nullable": true, + "description": "Number of unmatched resources. Only present when status is \"finished\"." + }, + "prior-monthly-cost": { + "type": "string", + "nullable": true, + "description": "Prior monthly cost as a decimal string. Only present when status is \"finished\"." + }, + "proposed-monthly-cost": { + "type": "string", + "nullable": true, + "description": "Proposed monthly cost as a decimal string. Only present when status is \"finished\"." + }, + "delta-monthly-cost": { + "type": "string", + "nullable": true, + "description": "Delta monthly cost as a decimal string. Only present when status is \"finished\"." } } } } }, - "policy-evaluations-envelope": { + "cost-estimates-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/policy-evaluations" + "$ref": "#/components/schemas/cost-estimates" } } }, - "policy-evaluations-id": { + "state-versions-envelope": { "type": "object", + "required": [ + "data" + ], "properties": { "data": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "policy-evaluations" - ] - } - } - }, - "links": { - "$ref": "#/components/schemas/related" + "$ref": "#/components/schemas/state-versions" } } }, - "policy-set-outcomes": { + "state-version-outputs": { "type": "object", - "required": [ - "type", - "attributes" - ], + "description": "State version outputs are the output values from a Terraform state file for a workspace. They include the name and value of the output, as well as a sensitive boolean if the value should be hidden by default in UIs. There is an additional attribute, \"value\" that can be any type, including null if the value is sensitive and part of a list response.", "properties": { "id": { "type": "string", @@ -24977,108 +31596,94 @@ "type": { "type": "string", "enum": [ - "policy-set-outcomes" + "state-version-outputs" ] }, "attributes": { "type": "object", "properties": { - "outcomes": { - "type": "array", - "nullable": true, - "items": { - "type": "object", - "properties": { - "enforcement_level": { - "type": "string", - "nullable": true - }, - "query": { - "type": "string", - "nullable": true - }, - "status": { - "type": "string" - }, - "policy_name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string" - }, - "output": { - "type": "array", - "nullable": true, - "items": {} - } - } - } - }, - "error": { - "type": "string", - "nullable": true - }, - "warnings": { - "type": "array", - "items": { - "type": "string" - } + "name": { + "type": "string" }, - "overridable": { + "sensitive": { "type": "boolean" }, - "policy-set-name": { - "type": "string" - }, - "policy-set-description": { + "type": { "type": "string", - "nullable": true - }, - "result-count": { - "type": "object", - "properties": { - "advisory-failed": { - "type": "integer" - }, - "mandatory-failed": { - "type": "integer" - }, - "passed": { - "type": "integer" - }, - "errored": { - "type": "integer" - } - } + "description": "The Terraform type of the output value (e.g. \"string\", \"number\", \"bool\", \"list\", \"map\", \"set\", \"object\", \"tuple\")." }, - "policy-tool-version": { - "type": "string" + "detailed-type": { + "description": "A detailed representation of the output type. May be a string for simple types or an array for complex types such as tuples and objects." } } }, - "relationships": { + "links": { + "$ref": "#/components/schemas/self" + } + } + }, + "state-version-outputs-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/state-version-outputs" + } + } + }, + "hyok-customer-key-versions-id": { + "type": "object", + "properties": { + "data": { "type": "object", "properties": { - "policy-evaluation": { - "$ref": "#/components/schemas/policy-evaluations-id" + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "hyok-customer-key-versions" + ] } } } } }, - "policy-set-outcomes-envelope": { + "oidc-configurations-id": { "type": "object", + "nullable": true, "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/policy-set-outcomes" + "type": "object", + "nullable": true, + "required": [ + "id", + "type" + ], + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "aws-oidc-configurations", + "azure-oidc-configurations", + "gcp-oidc-configurations", + "vault-oidc-configurations" + ] + } + } } } }, - "plan-exports": { + "hyok-configurations": { "type": "object", "required": [ "type", @@ -25092,273 +31697,315 @@ "type": { "type": "string", "enum": [ - "plan-exports" + "hyok-configurations" ] }, "attributes": { "type": "object", "properties": { - "data-type": { - "type": "string", - "enum": [ - "sentinel-mock-bundle-v0" - ] + "kek-id": { + "type": "string" }, - "status": { - "type": "string", - "enum": [ - "pending", - "queued", - "finished", - "expired", - "canceled", - "errored" - ] + "name": { + "type": "string" }, - "status-timestamps": { + "primary": { + "type": "boolean" + }, + "kms-options": { "type": "object", + "nullable": true, "properties": { - "pending-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "queued-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "finished-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "expired-at": { + "key-region": { "type": "string", - "format": "date-time", - "nullable": true + "description": "Only required with AWS KMS" }, - "canceled-at": { + "key-location": { "type": "string", - "format": "date-time", - "nullable": true + "description": "Only required with GCP KMS" }, - "errored-at": { + "key-ring-id": { "type": "string", - "format": "date-time", - "nullable": true + "description": "Only required with GCP KMS" } } - }, - "error-message": { - "type": "string", - "nullable": true } } }, "relationships": { "type": "object", "properties": { - "plan": { - "$ref": "#/components/schemas/plans-id" - } - } - }, - "links": { - "type": "object", - "properties": { - "self": { - "type": "string" + "organization": { + "readOnly": true, + "$ref": "#/components/schemas/organizations-id" }, - "download": { - "type": "string", - "nullable": true + "agent-pool": { + "$ref": "#/components/schemas/agent-pools-id" + }, + "hyok-customer-key-versions": { + "readOnly": true, + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/hyok-customer-key-versions-id" + } + } + } + }, + "oidc-configuration": { + "readOnly": true, + "$ref": "#/components/schemas/oidc-configurations-id", + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "aws-oidc-configurations", + "gcp-oidc-configurations", + "azure-oidc-configurations", + "vault-oidc-configurations" + ] + } + } + } + } } } } } }, - "plan-exports-envelope": { + "hyok-configurations-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/plan-exports" + "$ref": "#/components/schemas/hyok-configurations" } } }, - "state-versions-id": { + "aws-oidc-configurations": { "type": "object", "required": [ - "id", - "type" + "type", + "attributes" ], "properties": { "id": { - "type": "string" + "type": "string", + "readOnly": true }, "type": { "type": "string", "enum": [ - "state-versions" + "aws-oidc-configurations" ] + }, + "attributes": { + "type": "object", + "properties": { + "role-arn": { + "type": "string" + }, + "region": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "relationships": { + "type": "object", + "properties": { + "organization": { + "$ref": "#/components/schemas/organizations-id" + } + } } } }, - "applies": { + "gcp-oidc-configurations": { "type": "object", + "required": [ + "type", + "attributes" + ], "properties": { "id": { - "type": "string" + "type": "string", + "readOnly": true }, "type": { "type": "string", "enum": [ - "applies" + "gcp-oidc-configurations" ] }, "attributes": { "type": "object", "properties": { - "execution-details": { - "type": "object", - "readOnly": true, - "nullable": true, - "properties": { - "mode": { - "type": "string", - "enum": [ - "agent", - "remote", - "local" - ] - }, - "agent-id": { - "type": "string" - }, - "agent-name": { - "type": "string" - }, - "agent-pool-id": { - "type": "string" - }, - "agent-pool-name": { - "type": "string" - } - } + "service-account-email": { + "type": "string" }, - "status": { - "readOnly": true, + "region": { + "type": "string" + }, + "workload-provider-name": { "type": "string", - "enum": [ - "created", - "pending", - "queued", - "agent_queued", - "running", - "errored", - "canceled", - "finished", - "unreachable" - ] + "description": "Either the workload-provider-name or workload-pool-id and workload-provider-id must be provided" }, - "status-timestamps": { - "readOnly": true, - "type": "object", - "properties": { - "agent-queued-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "started-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "errored-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "canceled-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "force-canceled-at": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "finished-at": { - "type": "string", - "format": "date-time", - "nullable": true - } - } + "project-number": { + "type": "string" + }, + "workload-pool-id": { + "type": "string", + "description": "Either the workload-provider-name or workload-pool-id and workload-provider-id must be provided" + }, + "workload-provider-id": { + "type": "string", + "description": "Either the workload-provider-name or workload-pool-id and workload-provider-id must be provided" + }, + "type": { + "type": "string" + } + } + }, + "relationships": { + "type": "object", + "properties": { + "organization": { + "$ref": "#/components/schemas/organizations-id" + } + } + } + } + }, + "azure-oidc-configurations": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "azure-oidc-configurations" + ] + }, + "attributes": { + "type": "object", + "properties": { + "client-id": { + "type": "string" }, - "log-read-url": { - "readOnly": true, + "subscription-id": { "type": "string" }, - "resource-additions": { - "readOnly": true, - "type": "integer", - "nullable": true + "tenant-id": { + "type": "string" }, - "resource-changes": { - "readOnly": true, - "type": "integer", - "nullable": true + "type": { + "type": "string" + } + } + }, + "relationships": { + "type": "object", + "properties": { + "organization": { + "$ref": "#/components/schemas/organizations-id" + } + } + } + } + }, + "vault-oidc-configurations": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "vault-oidc-configurations" + ] + }, + "attributes": { + "type": "object", + "properties": { + "address": { + "type": "string" }, - "resource-destructions": { - "readOnly": true, - "type": "integer", - "nullable": true + "role": { + "type": "string" }, - "resource-imports": { - "readOnly": true, - "type": "integer", - "nullable": true + "namespace": { + "type": "string" + }, + "auth-path": { + "type": "string" + }, + "encoded-ca-cert": { + "type": "string" } } }, "relationships": { "type": "object", "properties": { - "state-versions": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/state-versions-id" - } - } - } + "organization": { + "$ref": "#/components/schemas/organizations-id" } } - }, - "links": { - "$ref": "#/components/schemas/self" } } }, - "applies-envelope": { + "oidc-configuration-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/applies" + "oneOf": [ + { + "$ref": "#/components/schemas/aws-oidc-configurations" + }, + { + "$ref": "#/components/schemas/gcp-oidc-configurations" + }, + { + "$ref": "#/components/schemas/azure-oidc-configurations" + }, + { + "$ref": "#/components/schemas/vault-oidc-configurations" + } + ] } } }, - "cost-estimates": { + "hyok-customer-key-versions": { "type": "object", "required": [ "type", @@ -25372,137 +32019,70 @@ "type": { "type": "string", "enum": [ - "cost-estimates" + "hyok-customer-key-versions" ] }, "attributes": { "type": "object", "properties": { - "error-message": { + "key-version": { "type": "string", - "nullable": true + "readOnly": true }, - "status": { + "created-at": { "type": "string", - "enum": [ - "pending", - "queued", - "finished", - "canceled", - "errored", - "unreachable", - "skipped_due_to_targeting" - ] - }, - "status-timestamps": { - "type": "object", - "properties": { - "pending-at": { - "type": "string", - "format": "date-time" - }, - "queued-at": { - "type": "string", - "format": "date-time" - }, - "finished-at": { - "type": "string", - "format": "date-time" - }, - "canceled-at": { - "type": "string", - "format": "date-time" - }, - "errored-at": { - "type": "string", - "format": "date-time" - }, - "skipped-due-to-targeting-at": { - "type": "string", - "format": "date-time" - } - } - }, - "resources": { - "type": "object", - "nullable": true, - "description": "Low-level cost estimation details, only present when status is \"finished\". The keys or structure of this hash may change over time.", - "properties": { - "matched": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": true - } - }, - "unmatched": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": true - } - } - } - }, - "resources-count": { - "type": "integer", - "nullable": true, - "description": "Total number of resources. Only present when status is \"finished\"." - }, - "matched-resources-count": { - "type": "integer", - "nullable": true, - "description": "Number of matched resources. Only present when status is \"finished\"." + "format": "date-time", + "readOnly": true }, - "unmatched-resources-count": { + "workspaces-secured": { "type": "integer", - "nullable": true, - "description": "Number of unmatched resources. Only present when status is \"finished\"." - }, - "prior-monthly-cost": { - "type": "string", - "nullable": true, - "description": "Prior monthly cost as a decimal string. Only present when status is \"finished\"." + "readOnly": true }, - "proposed-monthly-cost": { + "status": { "type": "string", - "nullable": true, - "description": "Proposed monthly cost as a decimal string. Only present when status is \"finished\"." + "readOnly": true, + "enum": [ + "available", + "revoking", + "revoked", + "revocation_failed" + ] }, - "delta-monthly-cost": { + "error": { "type": "string", "nullable": true, - "description": "Delta monthly cost as a decimal string. Only present when status is \"finished\"." + "readOnly": true + } + } + }, + "relationships": { + "type": "object", + "properties": { + "hyok-configuration": { + "readOnly": true, + "$ref": "#/components/schemas/hyok-configurations-id" } } } } }, - "cost-estimates-envelope": { + "hyok-customer-key-versions-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/cost-estimates" + "$ref": "#/components/schemas/hyok-customer-key-versions" } } }, - "state-versions-envelope": { + "hyok-encrypted-data-keys": { "type": "object", "required": [ - "data" + "type", + "attributes" ], - "properties": { - "data": { - "$ref": "#/components/schemas/state-versions" - } - } - }, - "state-version-outputs": { - "type": "object", - "description": "State version outputs are the output values from a Terraform state file for a workspace. They include the name and value of the output, as well as a sensitive boolean if the value should be hidden by default in UIs. There is an additional attribute, \"value\" that can be any type, including null if the value is sensitive and part of a list response.", "properties": { "id": { "type": "string", @@ -25511,40 +32091,46 @@ "type": { "type": "string", "enum": [ - "state-version-outputs" + "hyok-encrypted-data-keys" ] }, "attributes": { "type": "object", "properties": { - "name": { - "type": "string" - }, - "sensitive": { - "type": "boolean" + "encrypted-dek": { + "type": "string", + "readOnly": true }, - "type": { + "created-at": { "type": "string", - "description": "The Terraform type of the output value (e.g. \"string\", \"number\", \"bool\", \"list\", \"map\", \"set\", \"object\", \"tuple\")." + "format": "date-time", + "readOnly": true }, - "detailed-type": { - "description": "A detailed representation of the output type. May be a string for simple types or an array for complex types such as tuples and objects." + "customer-key-name": { + "type": "string", + "readOnly": true } } }, - "links": { - "$ref": "#/components/schemas/self" + "relationships": { + "type": "object", + "properties": { + "hyok-customer-key-version": { + "readOnly": true, + "$ref": "#/components/schemas/hyok-customer-key-versions-id" + } + } } } }, - "state-version-outputs-envelope": { + "hyok-encrypted-data-keys-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/state-version-outputs" + "$ref": "#/components/schemas/hyok-encrypted-data-keys" } } }, @@ -25921,7 +32507,7 @@ }, "policy-overrides": { "type": "boolean", - "description": "Whether the team can override policy checks within the project's workspaces. This field is available only when the `TEAM_OVERRIDE_POLICY_CHECKS` feature flag is enabled." + "description": "Whether the team can override policy checks within the project's workspaces." } } } @@ -26039,7 +32625,7 @@ }, "policy-overrides": { "type": "boolean", - "description": "Whether the team can override policy checks for the workspace. This field is available only when the `TEAM_OVERRIDE_POLICY_CHECKS` feature flag is enabled." + "description": "Whether the team can override policy checks for the workspace." } } }, @@ -26234,61 +32820,435 @@ "compare-url": { "type": "string" }, - "identifier": { - "type": "string" + "identifier": { + "type": "string" + }, + "is-pull-request": { + "type": "boolean" + }, + "on-default-branch": { + "type": "boolean" + }, + "pull-request-number": { + "type": "integer" + }, + "pull-request-url": { + "type": "string" + }, + "pull-request-title": { + "type": "string" + }, + "pull-request-body": { + "type": "string" + }, + "tag": { + "type": "string", + "nullable": true + }, + "sender-username": { + "type": "string" + }, + "sender-avatar-url": { + "type": "string" + }, + "sender-html-url": { + "type": "string" + } + } + }, + "relationships": { + "type": "object", + "properties": { + "created-by": { + "$ref": "#/components/schemas/users-id" + } + } + }, + "links": { + "$ref": "#/components/schemas/self" + } + } + }, + "oauth-clients-id": { + "type": "object", + "properties": { + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "oauth-clients" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "oauth-tokens-id": { + "type": "object", + "properties": { + "data": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "oauth-tokens" + ] + } + } + }, + "links": { + "$ref": "#/components/schemas/related" + } + } + }, + "vcs-events": { + "type": "object", + "required": [ + "type", + "attributes" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "vcs-events" + ] + }, + "attributes": { + "type": "object", + "properties": { + "created-at": { + "type": "string", + "format": "date-time", + "readOnly": true + }, + "level": { + "type": "string" + }, + "message": { + "type": "string", + "nullable": true + }, + "organization-id": { + "type": "integer" + }, + "suggested-action": { + "type": "string", + "nullable": true + } + } + }, + "relationships": { + "type": "object", + "properties": { + "oauth-client": { + "$ref": "#/components/schemas/oauth-clients-id" + }, + "oauth-token": { + "$ref": "#/components/schemas/oauth-tokens-id" + } + } + } + } + }, + "vcs-repo-check": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "An identifier for the repository check (typically the repository identifier)" + }, + "type": { + "type": "string", + "enum": [ + "vcs-repo-check" + ] + }, + "attributes": { + "type": "object", + "properties": { + "exists": { + "type": "boolean", + "description": "Whether the repository exists and is accessible" + }, + "identifier": { + "type": "string", + "description": "The repository identifier that was checked" + } + } + } + } + }, + "vcs-repo-check-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/vcs-repo-check" + } + } + }, + "registry-module-address-validations": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "A unique identifier for this validation result" + }, + "type": { + "type": "string", + "enum": [ + "registry-module-address-validations" + ] + }, + "attributes": { + "type": "object", + "properties": { + "module-name": { + "type": "string", + "description": "The module name that was validated" + }, + "provider-name": { + "type": "string", + "description": "The provider name that was validated" + }, + "valid": { + "type": "boolean", + "description": "Whether the module name and provider combination is available" + } + } + } + } + }, + "registry-module-address-validations-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/registry-module-address-validations" + } + } + }, + "registry-modules": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "type": { + "type": "string", + "enum": [ + "registry-modules" + ] + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string", + "readOnly": true + }, + "namespace": { + "type": "string", + "readOnly": true }, - "is-pull-request": { - "type": "boolean" + "provider": { + "type": "string", + "readOnly": true }, - "on-default-branch": { - "type": "boolean" + "registry-name": { + "type": "string", + "readOnly": true }, - "pull-request-number": { - "type": "integer" + "status": { + "type": "string", + "readOnly": true }, - "pull-request-url": { - "type": "string" + "publishing-mechanism": { + "type": "string", + "readOnly": true, + "enum": [ + "branch", + "git_tag", + "non_vcs" + ] }, - "pull-request-title": { - "type": "string" + "no-code": { + "type": "boolean", + "description": "Whether the module is a no-code module." }, - "pull-request-body": { - "type": "string" + "version-statuses": { + "type": "array", + "readOnly": true, + "items": { + "type": "object" + } }, - "tag": { + "created-at": { "type": "string", - "nullable": true + "format": "date-time", + "readOnly": true }, - "sender-username": { - "type": "string" + "updated-at": { + "type": "string", + "format": "date-time", + "readOnly": true }, - "sender-avatar-url": { - "type": "string" + "vcs-repo": { + "type": "object", + "description": "The VCS connection and publishing settings for the module. Supplying a\nchanged `identifier`, `oauth-token-id`, or `github-app-installation-id`\nre-points the module to a different VCS source; supplying only\n`branch`, `tags`, or `tag-prefix` changes the publishing mechanism in\nplace.\n", + "properties": { + "identifier": { + "type": "string", + "description": "The repository from which to ingress the configuration, e.g. \"org/repo\"." + }, + "display-identifier": { + "type": "string", + "description": "The display identifier for the repository. For most VCS providers\noutside of Bitbucket Cloud, this matches `identifier`.\n" + }, + "oauth-token-id": { + "type": "string", + "description": "The VCS Connection (OAuth Connection + Token) to use, obtained from\nthe oauth-tokens endpoint. Mutually exclusive with\n`github-app-installation-id`.\n" + }, + "github-app-installation-id": { + "type": "string", + "description": "The VCS Connection GitHub App Installation to use. Mutually\nexclusive with `oauth-token-id`.\n" + }, + "branch": { + "type": "string", + "description": "The repository branch to publish the module from (branch-based publishing)." + }, + "tags": { + "type": "boolean", + "description": "Whether the module uses the tag-based publishing workflow." + }, + "tag-prefix": { + "type": "string", + "nullable": true, + "description": "An optional prefix used to filter tags for tag-based publishing." + }, + "ingress-submodules": { + "type": "boolean", + "description": "Whether submodules should be fetched when cloning the repository." + }, + "source-directory": { + "type": "string", + "nullable": true, + "description": "The directory within the repository where the module is located." + } + } }, - "sender-html-url": { - "type": "string" + "test-config": { + "type": "object", + "nullable": true, + "description": "Optional test configuration for the module. Present for branch-based\nmodules and non-VCS private modules, and `null` when the module has no\ntest configuration. Supplying `tests-enabled`, `agent-execution-mode`,\nor `agent-pool-id` configures testing for the module; when omitted,\ntesting defaults to disabled with remote execution.\n", + "properties": { + "id": { + "type": "string", + "readOnly": true + }, + "tests-enabled": { + "type": "boolean", + "default": false, + "description": "Whether testing is enabled for the module." + }, + "agent-execution-mode": { + "type": "string", + "default": "remote", + "description": "The execution mode used to run tests.", + "enum": [ + "remote", + "agent" + ] + }, + "agent-pool-id": { + "type": "string", + "description": "The ID of the agent pool used when `agent-execution-mode` is `agent`.", + "nullable": true + }, + "agent-pool-name": { + "type": "string", + "readOnly": true, + "description": "The name of the agent pool used when `agent-execution-mode` is `agent`.", + "nullable": true + } + } + }, + "permissions": { + "type": "object", + "readOnly": true, + "properties": { + "can-delete": { + "type": "boolean" + }, + "can-resync": { + "type": "boolean" + }, + "can-retry": { + "type": "boolean" + } + } } } }, + "links": { + "$ref": "#/components/schemas/self" + }, "relationships": { "type": "object", "properties": { - "created-by": { - "$ref": "#/components/schemas/users-id" + "organization": { + "$ref": "#/components/schemas/links_related" + }, + "no-code-modules": { + "$ref": "#/components/schemas/links_related" } } - }, - "links": { - "$ref": "#/components/schemas/self" } } }, - "oauth-clients-id": { + "registry-modules-envelope": { + "type": "object", + "required": [ + "data" + ], + "properties": { + "data": { + "$ref": "#/components/schemas/registry-modules" + } + } + }, + "test-runs-id": { "type": "object", "properties": { "data": { "type": "object", - "nullable": true, "properties": { "id": { "type": "string" @@ -26296,17 +33256,14 @@ "type": { "type": "string", "enum": [ - "oauth-clients" + "test-runs" ] } } - }, - "links": { - "$ref": "#/components/schemas/related" } } }, - "oauth-tokens-id": { + "test-run-cleanups-id": { "type": "object", "properties": { "data": { @@ -26319,7 +33276,7 @@ "type": { "type": "string", "enum": [ - "oauth-tokens" + "test-run-cleanups" ] } } @@ -26329,7 +33286,7 @@ } } }, - "vcs-events": { + "test-run-cleanups": { "type": "object", "required": [ "type", @@ -26343,7 +33300,7 @@ "type": { "type": "string", "enum": [ - "vcs-events" + "test-run-cleanups" ] }, "attributes": { @@ -26354,114 +33311,69 @@ "format": "date-time", "readOnly": true }, - "level": { - "type": "string" + "updated-at": { + "type": "string", + "format": "date-time", + "readOnly": true }, - "message": { + "status": { "type": "string", - "nullable": true + "enum": [ + "pending", + "queued", + "running", + "finished", + "canceled", + "errored" + ] }, - "organization-id": { - "type": "integer" + "status-timestamps": { + "type": "object", + "additionalProperties": { + "type": "string", + "format": "date-time" + } }, - "suggested-action": { - "type": "string", - "nullable": true - } - } - }, - "relationships": { - "type": "object", - "properties": { - "oauth-client": { - "$ref": "#/components/schemas/oauth-clients-id" + "repair-mode": { + "type": "boolean" }, - "oauth-token": { - "$ref": "#/components/schemas/oauth-tokens-id" - } - } - } - } - }, - "vcs-repo-check": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "An identifier for the repository check (typically the repository identifier)" - }, - "type": { - "type": "string", - "enum": [ - "vcs-repo-check" - ] - }, - "attributes": { - "type": "object", - "properties": { - "exists": { - "type": "boolean", - "description": "Whether the repository exists and is accessible" + "filters": { + "type": "array", + "nullable": true, + "items": { + "type": "string" + } }, - "identifier": { - "type": "string", - "description": "The repository identifier that was checked" + "result-summary": { + "type": "object", + "additionalProperties": true } } - } - } - }, - "vcs-repo-check-envelope": { - "type": "object", - "required": [ - "data" - ], - "properties": { - "data": { - "$ref": "#/components/schemas/vcs-repo-check" - } - } - }, - "registry-module-address-validations": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "A unique identifier for this validation result" - }, - "type": { - "type": "string", - "enum": [ - "registry-module-address-validations" - ] }, - "attributes": { + "relationships": { "type": "object", "properties": { - "module-name": { - "type": "string", - "description": "The module name that was validated" + "test-run": { + "$ref": "#/components/schemas/test-runs-id" }, - "provider-name": { - "type": "string", - "description": "The provider name that was validated" + "created-by": { + "$ref": "#/components/schemas/users-id" }, - "valid": { - "type": "boolean", - "description": "Whether the module name and provider combination is available" + "previous-test-run-cleanup": { + "$ref": "#/components/schemas/test-run-cleanups-id" } } } } }, - "registry-module-address-validations-envelope": { + "test-run-cleanups-envelope": { "type": "object", "required": [ "data" ], "properties": { "data": { - "$ref": "#/components/schemas/registry-module-address-validations" + "$ref": "#/components/schemas/test-run-cleanups" } } }, diff --git a/internal/pkg/resource/registry.go b/internal/pkg/resource/registry.go index b5dab28..dac8480 100644 --- a/internal/pkg/resource/registry.go +++ b/internal/pkg/resource/registry.go @@ -4,57 +4,147 @@ package resource import ( + "slices" "sort" "strings" ) +// A list of resource types to assist certain commands with identifying, retrieving, and managing +// resources within the system. This list doesn't have to be complete to be effective, but can +// be useful for prediction, column display, and destroy permissions. + var registry = []Resource{ { - Type: "workspaces", - Aliases: []string{"ws", "workspace"}, - IDPrefix: "ws-", - PathGet: "/workspaces/{id}", - PathList: "/organizations/{organization_name}/workspaces", - PathCreate: "/organizations/{organization_name}/workspaces", - Resolvable: true, - Columns: []string{"name", "description", "project", "execution-mode", "locked", "resource-count"}, - ExcludeColumns: []string{"actions"}, + Type: "agents", + Aliases: []string{"agent"}, + IDPrefix: "agent-", + PathGet: "/agents/{id}", + Destroyable: Destroyable, + }, + { + Type: "agent-pools", + Aliases: []string{"apool", "agent-pool"}, + IDPrefix: "apool-", + PathGet: "/agent-pools/{id}", + PathList: "/organizations/{organization_name}/agent-pools", + PathCreate: "/organizations/{organization_name}/agent-pools", + Columns: []string{"name", "organization-scoped", "agent-count"}, + Destroyable: Destroyable, + }, + { + Type: "applies", + Aliases: []string{"apply"}, + IDPrefix: "apply-", + PathGet: "/applies/{id}", + Columns: []string{"status", "status-timestamps", "log-read-url"}, + Destroyable: NotDestroyable, + }, + { + Type: "assessment-results", + IDPrefix: "asmtres-", + PathGet: "/assessment-results/{id}", + Destroyable: NotDestroyable, + }, + { + Type: "authentication-tokens", + IDPrefix: "at-", + PathGet: "/authentication-tokens/{id}", + Destroyable: Destroyable, + }, + { + Type: "cidr-range-lists", + IDPrefix: "crl-", + PathGet: "/cidr-range-lists/{id}", + Destroyable: Destroyable, + }, + { + Type: "comments", + IDPrefix: "wsc-", + PathGet: "/comments/{id}", + Destroyable: NotDestroyable, + }, + { + Type: "configuration-versions", + Aliases: []string{"cv", "config-version", "configuration-version"}, + IDPrefix: "cv-", + PathGet: "/configuration-versions/{id}", + Columns: []string{"status", "speculative", "provisional"}, + Destroyable: NotDestroyable, + }, + { + Type: "cost-estimates", + Aliases: []string{"cost-estimate", "ce"}, + IDPrefix: "ce-", + PathGet: "/cost-estimates/{id}", + Columns: []string{"status", "delta-monthly-cost", "proposed-monthly-cost"}, + Destroyable: NotDestroyable, }, { - Type: "runs", - Aliases: []string{"run"}, - IDPrefix: "run-", - PathGet: "/runs/{id}", - Columns: []string{"message", "status", "is-destroy", "has-changes"}, + Type: "explorer-saved-queries", + IDPrefix: "sq-", + PathGet: "/organizations/{organization_name}/explorer/views/{id}", + PathCreate: "/organizations/{organization_name}/explorer/views", + Destroyable: Destroyable, }, { - Type: "projects", - Aliases: []string{"prj", "project"}, - IDPrefix: "prj-", - PathGet: "/projects/{id}", - PathList: "/organizations/{organization_name}/projects", - PathCreate: "/organizations/{organization_name}/projects", - Resolvable: true, - Columns: []string{"name", "description", "organization-name"}, + Type: "feature-sets", + IDPrefix: "fs-", + Aliases: []string{"feature-set"}, + PathList: "/organizations/{organization_name}/feature-sets", + Destroyable: NotDestroyable, + ExcludeColumns: []string{"description"}, }, { - Type: "teams", - Aliases: []string{"team"}, - IDPrefix: "team-", - PathGet: "/teams/{id}", - PathList: "/organizations/{organization_name}/teams", - PathCreate: "/organizations/{organization_name}/teams", - Resolvable: true, + Type: "github-app-installations", + IDPrefix: "ghain-", + PathGet: "/github-app/installation/{id}", + Destroyable: NotDestroyable, }, { - Type: "varsets", - Aliases: []string{"varset", "variable-sets", "variable-set"}, - IDPrefix: "varset-", - PathGet: "/varsets/{id}", - PathList: "/organizations/{organization_name}/varsets", - PathCreate: "/organizations/{organization_name}/varsets", - Resolvable: true, - Columns: []string{"name", "description", "global", "priority"}, + Type: "gpg-keys", + Aliases: []string{"gpg-key"}, + Destroyable: Destroyable, + }, + { + Type: "hyok-configurations", + IDPrefix: "hyok-", + PathGet: "/hyok-configurations/{id}", + Destroyable: Destroyable, + }, + { + Type: "hyok-customer-key-versions", + IDPrefix: "keyv-", + PathGet: "/hyok-customer-key-versions/{id}", + Destroyable: NotDestroyable, + }, + { + Type: "hyok-encrypted-data-keys", + IDPrefix: "dek-", + PathGet: "/hyok-encrypted-data-keys/{id}", + Destroyable: NotDestroyable, + }, + { + Type: "notification-configurations", + Aliases: []string{"notification-configuration", "nc"}, + IDPrefix: "nc-", + PathGet: "/notification-configurations/{id}", + Columns: []string{"name", "destination-type", "enabled", "triggers"}, + Destroyable: Destroyable, + }, + { + Type: "oauth-clients", + Aliases: []string{"oauth-client", "oc"}, + IDPrefix: "oc-", + PathGet: "/oauth-clients/{id}", + PathCreate: "/organizations/{organization_name}/oauth-clients", + Destroyable: Destroyable, + }, + { + Type: "oauth-tokens", + Aliases: []string{"oauth-token", "ot"}, + IDPrefix: "ot-", + PathGet: "/oauth-tokens/{id}", + Destroyable: Destroyable, }, { Type: "organizations", @@ -63,114 +153,181 @@ var registry = []Resource{ PathList: "/organizations", Columns: []string{"name", "email", "external-id", "access-beta-tools", "stacks-enabled"}, ExcludeColumns: []string{"id"}, + Destroyable: DestroyableButSensitive, + }, + { + Type: "organization-memberships", + Aliases: []string{"organization-membership", "org-membership"}, + IDPrefix: "ou-", + PathGet: "/organization-memberships/{id}", + PathList: "/organizations/{organization_name}/organization-memberships", + Columns: []string{"email", "status", "role"}, + Destroyable: Destroyable, + }, + { + Type: "plans", + Aliases: []string{"plan"}, + IDPrefix: "plan-", + PathGet: "/plans/{id}", + Columns: []string{"status", "has-changes", "generated-configuration"}, + Destroyable: NotDestroyable, + }, + { + Type: "plan-exports", + Aliases: []string{"plan-export"}, + IDPrefix: "pe-", + PathGet: "/plan-exports/{id}", + Columns: []string{"status", "data-type", "url"}, + Destroyable: Destroyable, + }, + { + Type: "policies", + Aliases: []string{"policy"}, + IDPrefix: "pol-", + PathGet: "/policies/{id}", + Destroyable: Destroyable, + }, + { + Type: "policy-checks", + Aliases: []string{"policy-check"}, + IDPrefix: "polchk-", + PathGet: "/policy-checks/{id}", + Columns: []string{"status", "scope", "actions", "permissions"}, + Destroyable: NotDestroyable, + }, + { + Type: "policy-evaluations", + Aliases: []string{"policy-evaluation"}, + Columns: []string{"status", "result-count", "passed"}, + Destroyable: NotDestroyable, + }, + { + Type: "policy-sets", + Aliases: []string{"policy-set", "polset"}, + IDPrefix: "polset-", + PathGet: "/policy-sets/{id}", + PathList: "/organizations/{organization_name}/policy-sets", + PathCreate: "/organizations/{organization_name}/policy-sets", + Columns: []string{"name", "kind", "global", "overridable"}, + Destroyable: Destroyable, + }, + { + Type: "projects", + Aliases: []string{"prj", "project"}, + IDPrefix: "prj-", + PathGet: "/projects/{id}", + PathList: "/organizations/{organization_name}/projects", + PathCreate: "/organizations/{organization_name}/projects", + Resolvable: true, + Columns: []string{"name", "description", "organization-name"}, + Destroyable: DestroyableButSensitive, }, { - Type: "plans", - Aliases: []string{"plan"}, - IDPrefix: "plan-", - PathGet: "/plans/{id}", - Columns: []string{"status", "has-changes", "generated-configuration"}, + Type: "provider-sets", + Aliases: []string{"provider-set", "provset"}, + IDPrefix: "provset-", + PathGet: "/provider-sets/{id}", + PathList: "/organizations/{organization_name}/provider-sets", + PathCreate: "/organizations/{organization_name}/provider-sets", + Columns: []string{"name", "provider-source", "global", "priority", "updated-at"}, + ExcludeColumns: []string{"configuration-hcl"}, + Destroyable: Destroyable, }, { - Type: "applies", - Aliases: []string{"apply"}, - IDPrefix: "apply-", - PathGet: "/applies/{id}", - Columns: []string{"status", "status-timestamps", "log-read-url"}, + Type: "queries", + IDPrefix: "query-", + PathGet: "/queries/{id}", + Destroyable: NotDestroyable, }, { - Type: "state-versions", - Aliases: []string{"sv", "state-version"}, - IDPrefix: "sv-", - PathGet: "/state-versions/{id}", - Columns: []string{"serial", "status", "resource-count", "size"}, + Type: "registry-modules", + Aliases: []string{"registry-module"}, + IDPrefix: "mod-", + Destroyable: Destroyable, }, { - Type: "policy-sets", - Aliases: []string{"policy-set", "polset"}, - IDPrefix: "polset-", - PathGet: "/policy-sets/{id}", - PathList: "/organizations/{organization_name}/policy-sets", - PathCreate: "/organizations/{organization_name}/policy-sets", - Columns: []string{"name", "kind", "global", "overridable"}, + Type: "registry-module-versions", + Aliases: []string{"registry-module-version"}, + IDPrefix: "modver-", + Destroyable: NotDestroyable, }, { - Type: "vars", - Aliases: []string{"var", "variable", "variables"}, - IDPrefix: "var-", - PathGet: "/vars/{id}", - Columns: []string{"key", "value", "category", "hcl", "sensitive"}, + Type: "registry-providers", + Aliases: []string{"registry-provider"}, + IDPrefix: "prov-", + Destroyable: Destroyable, }, { - Type: "agent-pools", - Aliases: []string{"apool", "agent-pool"}, - IDPrefix: "apool-", - PathGet: "/agent-pools/{id}", - PathList: "/organizations/{organization_name}/agent-pools", - PathCreate: "/organizations/{organization_name}/agent-pools", - Columns: []string{"name", "organization-scoped", "agent-count"}, + Type: "registry-provider-versions", + IDPrefix: "provver-", + Destroyable: Destroyable, }, { - Type: "configuration-versions", - Aliases: []string{"cv", "config-version", "configuration-version"}, - IDPrefix: "cv-", - PathGet: "/configuration-versions/{id}", - Columns: []string{"status", "speculative", "provisional"}, + Type: "registry-provider-version-platforms", + IDPrefix: "provpltfrm-", + Destroyable: Destroyable, }, { - Type: "cost-estimates", - Aliases: []string{"cost-estimate", "ce"}, - IDPrefix: "ce-", - PathGet: "/cost-estimates/{id}", - Columns: []string{"status", "delta-monthly-cost", "proposed-monthly-cost"}, + Type: "reserved-tag-keys", + IDPrefix: "rtk-", + Destroyable: Destroyable, }, { - Type: "notification-configurations", - Aliases: []string{"notification-configuration", "nc"}, - IDPrefix: "nc-", - PathGet: "/notification-configurations/{id}", - Columns: []string{"name", "destination-type", "enabled", "triggers"}, + Type: "runs", + Aliases: []string{"run"}, + IDPrefix: "run-", + PathGet: "/runs/{id}", + Columns: []string{"message", "status", "is-destroy", "has-changes"}, + Destroyable: NotDestroyable, }, { - Type: "organization-memberships", - Aliases: []string{"organization-membership", "org-membership"}, - IDPrefix: "ou-", - PathGet: "/organization-memberships/{id}", - PathList: "/organizations/{organization_name}/organization-memberships", - Columns: []string{"email", "status", "role"}, + Type: "run-tasks", + Aliases: []string{"run-task"}, + IDPrefix: "task-", + PathGet: "/tasks/{id}", + Columns: []string{"name", "url", "category", "enabled"}, + Destroyable: Destroyable, }, { - Type: "plan-exports", - Aliases: []string{"plan-export"}, - IDPrefix: "pe-", - PathGet: "/plan-exports/{id}", - Columns: []string{"status", "data-type", "url"}, + Type: "run-triggers", + Aliases: []string{"run-trigger"}, + IDPrefix: "rt-", + PathGet: "/run-triggers/{id}", + Columns: []string{"name", "sourceable-name", "workspace-name"}, + Destroyable: Destroyable, }, { - Type: "policy-checks", - Aliases: []string{"policy-check"}, - IDPrefix: "polchk-", - PathGet: "/policy-checks/{id}", - Columns: []string{"status", "scope", "actions", "permissions"}, + Type: "ssh-keys", + IDPrefix: "ssh-", + PathGet: "/ssh-keys/{id}", + PathCreate: "/organizations/{organization_name}/ssh-keys", + Destroyable: Destroyable, }, { - Type: "policy-evaluations", - Aliases: []string{"policy-evaluation"}, - Columns: []string{"status", "result-count", "passed"}, + Type: "stacks", + IDPrefix: "st-", + PathGet: "/stacks/{id}", + Destroyable: DestroyableRecoverable, }, { - Type: "run-tasks", - Aliases: []string{"run-task"}, - IDPrefix: "task-", - PathGet: "/tasks/{id}", - Columns: []string{"name", "url", "category", "enabled"}, + Type: "stack-configurations", + IDPrefix: "stc-", + PathGet: "/stack-configurations/{id}", + Destroyable: NotDestroyable, }, { - Type: "run-triggers", - Aliases: []string{"run-trigger"}, - IDPrefix: "rt-", - PathGet: "/run-triggers/{id}", - Columns: []string{"name", "sourceable-name", "workspace-name"}, + Type: "stack-states", + IDPrefix: "sts-", + PathGet: "/stack-states/{id}", + Destroyable: NotDestroyable, + }, + { + Type: "state-versions", + Aliases: []string{"sv", "state-version"}, + IDPrefix: "sv-", + PathGet: "/state-versions/{id}", + Columns: []string{"serial", "status", "resource-count", "size"}, + Destroyable: NotDestroyable, }, { Type: "state-version-outputs", @@ -179,13 +336,15 @@ var registry = []Resource{ PathGet: "/state-version-outputs/{id}", Columns: []string{"name", "sensitive", "type"}, ExcludeColumns: []string{"detailed-type"}, + Destroyable: NotDestroyable, }, { - Type: "subscriptions", - Aliases: []string{"subscription"}, - IDPrefix: "sub-", - PathGet: "/subscriptions/{id}", - Columns: []string{"status", "plan-name", "quantity"}, + Type: "subscriptions", + Aliases: []string{"subscription"}, + IDPrefix: "sub-", + PathGet: "/subscriptions/{id}", + Columns: []string{"status", "plan-name", "quantity"}, + Destroyable: NotDestroyable, }, { Type: "task-stages", @@ -194,54 +353,86 @@ var registry = []Resource{ Columns: []string{"status", "stage", "task-result-count"}, }, { - Type: "policies", - Aliases: []string{"policy"}, - IDPrefix: "pol-", - PathGet: "/policies/{id}", + Type: "teams", + Aliases: []string{"team"}, + IDPrefix: "team-", + PathGet: "/teams/{id}", + PathList: "/organizations/{organization_name}/teams", + PathCreate: "/organizations/{organization_name}/teams", + Resolvable: true, + Destroyable: Destroyable, + }, + { + Type: "team-projects", + IDPrefix: "tprj-", + PathGet: "/team-projects/{id}", + Destroyable: Destroyable, }, { - Type: "feature-sets", - Aliases: []string{"feature-set"}, - PathList: "/organizations/{organization_name}/feature-sets", + Type: "team-workspaces", + IDPrefix: "tws-", + PathGet: "/team-workspaces/{id}", + Destroyable: Destroyable, }, { - Type: "oauth-clients", - Aliases: []string{"oauth-client", "oc"}, - IDPrefix: "oc-", - PathGet: "/oauth-clients/{id}", + Type: "test-runs", + IDPrefix: "trun-", + Destroyable: NotDestroyable, }, { - Type: "oauth-tokens", - Aliases: []string{"oauth-token", "ot"}, - IDPrefix: "ot-", - PathGet: "/oauth-tokens/{id}", + Type: "users", + IDPrefix: "usr-", + PathGet: "/users/{id}", + Destroyable: NotDestroyable, }, { - Type: "registry-providers", - Aliases: []string{"registry-provider"}, - IDPrefix: "prov-", + Type: "vars", + Aliases: []string{"var", "variable", "variables"}, + IDPrefix: "var-", + PathGet: "/vars/{id}", + Columns: []string{"key", "value", "category", "hcl", "sensitive"}, + Destroyable: Destroyable, }, { - Type: "gpg-keys", - Aliases: []string{"gpg-key"}, - IDPrefix: "gpg-", + Type: "varsets", + Aliases: []string{"varset", "variable-sets", "variable-set"}, + IDPrefix: "varset-", + PathGet: "/varsets/{id}", + PathList: "/organizations/{organization_name}/varsets", + PathCreate: "/organizations/{organization_name}/varsets", + Resolvable: true, + Columns: []string{"name", "description", "global", "priority"}, + Destroyable: Destroyable, }, { - Type: "agents", - Aliases: []string{"agent"}, - IDPrefix: "agent-", - PathGet: "/agents/{id}", + Type: "workspaces", + Aliases: []string{"ws", "workspace"}, + IDPrefix: "ws-", + PathGet: "/workspaces/{id}", + PathList: "/organizations/{organization_name}/workspaces", + PathCreate: "/organizations/{organization_name}/workspaces", + Resolvable: true, + Columns: []string{"name", "description", "project", "execution-mode", "locked", "resource-count"}, + ExcludeColumns: []string{"actions"}, + Destroyable: DestroyableRecoverable, }, } -// ByName matches the canonical Type or any Alias, case-insensitive. +func init() { + slices.SortFunc(registry, func(a, b Resource) int { + return strings.Compare(a.Type, b.Type) + }) +} + +// ByNameOrAlias matches the canonical Type or any Alias, case-insensitive. // Returns nil if not found. -func ByName(name string) *Resource { +func ByNameOrAlias(name string) *Resource { lower := strings.ToLower(name) + if exact, ok := ByName(lower); ok { + return &exact + } + for i := range registry { - if strings.ToLower(registry[i].Type) == lower { - return ®istry[i] - } for _, alias := range registry[i].Aliases { if strings.ToLower(alias) == lower { return ®istry[i] @@ -310,43 +501,62 @@ func CreatableNames() []string { return names } -// IsResolvableType returns true if the given type name (e.g. "workspaces") -// supports name-to-ID resolution via the API. -func IsResolvableType(typeName string) bool { - for i := range registry { - if registry[i].Type == typeName && registry[i].Resolvable { - return true +// AllDestroyable returns all registered resources that are destroyable. +func AllDestroyable() []Resource { + out := make([]Resource, 0, len(registry)-20) // Estimated number of NotDestroyable resources above + for _, r := range registry { + if r.Destroyable != NotDestroyable { + out = append(out, r) } } - return false + return out } -// IDPrefixForType returns the ID prefix for the given type name, or "" if unknown. -func IDPrefixForType(typeName string) string { - for i := range registry { - if registry[i].Type == typeName { - return registry[i].IDPrefix - } +// ByName looks up a resource by type name and returns it along with a boolean indicating if it was found. +// Presumes that the registry is sorted by the Type field. +func ByName(typeName string) (Resource, bool) { + index, ok := slices.BinarySearchFunc(registry, Resource{Type: typeName}, func(a, b Resource) int { + return strings.Compare(a.Type, b.Type) + }) + if ok { + return registry[index], true } - return "" + return Resource{}, false } // ColumnsForType returns the preferred display columns for the given type, or nil. func ColumnsForType(typeName string) []string { - for i := range registry { - if registry[i].Type == typeName { - return registry[i].Columns - } + r, ok := ByName(typeName) + if !ok { + return nil } - return nil + return r.Columns } // ExcludeColumnsForType returns columns to exclude for the given type, or nil. func ExcludeColumnsForType(typeName string) []string { - for i := range registry { - if registry[i].Type == typeName { - return registry[i].ExcludeColumns - } + r, ok := ByName(typeName) + if !ok { + return nil } - return nil + return r.ExcludeColumns +} + +// IDPrefixForType returns the ID prefix for the given type name, or "" if unknown. +func IDPrefixForType(typeName string) string { + r, ok := ByName(typeName) + if !ok { + return "" + } + return r.IDPrefix +} + +// IsResolvableType returns true if the given type name (e.g. "workspaces") +// supports name-to-ID resolution via the API. +func IsResolvableType(typeName string) bool { + r, ok := ByName(typeName) + if !ok { + return false + } + return r.Resolvable } diff --git a/internal/pkg/resource/registry_test.go b/internal/pkg/resource/registry_test.go index 6524188..152c18e 100644 --- a/internal/pkg/resource/registry_test.go +++ b/internal/pkg/resource/registry_test.go @@ -80,12 +80,37 @@ func TestByName(t *testing.T) { input: "cv", wantType: "configuration-versions", }, + { + name: "provider sets canonical", + input: "provider-sets", + wantType: "provider-sets", + }, + { + name: "provider set alias", + input: "provider-set", + wantType: "provider-sets", + }, + { + name: "provider set short alias", + input: "provset", + wantType: "provider-sets", + }, + { + name: "provider sets mixed case", + input: "Provider-Sets", + wantType: "provider-sets", + }, + { + name: "provider set uppercase alias", + input: "PROVSET", + wantType: "provider-sets", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() - got := ByName(tt.input) + got := ByNameOrAlias(tt.input) if tt.wantNil { assert.Nil(t, got) } else { diff --git a/internal/pkg/resource/resource.go b/internal/pkg/resource/resource.go index ddfb923..58c4e22 100644 --- a/internal/pkg/resource/resource.go +++ b/internal/pkg/resource/resource.go @@ -4,15 +4,30 @@ // Package resource provides a registry of known HCP Terraform API resource types. package resource +// Destroyability indicates whether a resource can be destroyed. +type Destroyability int + +const ( + // NotDestroyable indicates that the resource cannot be destroyed. + NotDestroyable Destroyability = iota + // Destroyable indicates that the resource can be destroyed normally. + Destroyable + // DestroyableRecoverable indicates that the resource can be destroyed but also can be recovered. + DestroyableRecoverable + // DestroyableButSensitive indicates that the resource can be destroyed but is considered irreversible/sensitive. + DestroyableButSensitive +) + // Resource describes a known API resource type. type Resource struct { - Type string // JSON:API type: "workspaces" - Aliases []string // shorthand: ["ws", "workspace"] - IDPrefix string // "ws-" (empty if unknown) - PathGet string // "/workspaces/{id}" - PathList string // "/organizations/{organization_name}/workspaces" (empty if not top-level listable) - PathCreate string // "/organizations/{organization_name}/workspaces" (empty if not supported) - Resolvable bool // true if the API supports name-to-ID resolution for this type - Columns []string // most important attributes for display (nil = auto-detect) - ExcludeColumns []string // attributes to exclude from display + Type string // JSON:API type: "workspaces" + Aliases []string // shorthand: ["ws", "workspace"] + IDPrefix string // "ws-" (empty if unknown) + PathGet string // "/workspaces/{id}" + PathList string // "/organizations/{organization_name}/workspaces" (empty if not top-level listable) + PathCreate string // "/organizations/{organization_name}/workspaces" (empty if not supported) + Resolvable bool // true if the API supports name-to-ID resolution for this type + Columns []string // most important attributes for display (nil = auto-detect) + ExcludeColumns []string // attributes to exclude from display + Destroyable Destroyability // indicates if and how this resource can be destroyed } diff --git a/skills/embed.go b/skills/embed.go index c2cba52..098b488 100644 --- a/skills/embed.go +++ b/skills/embed.go @@ -10,3 +10,16 @@ import "embed" // //go:embed tfctl var FS embed.FS + +// EmbeddedSkillHash returns the SHA256 hash of the embedded SKILL.md file. +func EmbeddedSkillHash() string { + file, err := FS.Open(TFCTLSkillPath) + if err != nil { + return "" + } + hash, err := hashSHA256Hex(file) + if err != nil { + return "" + } + return hash +} diff --git a/skills/existing.go b/skills/existing.go new file mode 100644 index 0000000..35ac586 --- /dev/null +++ b/skills/existing.go @@ -0,0 +1,117 @@ +package skills + +import ( + "bufio" + "crypto/sha256" + "encoding/hex" + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "github.com/hashicorp/tfctl-cli/version" +) + +// InstalledSkill represents a skill that is already installed on the system. +type InstalledSkill struct { + path string + global bool + agentName string +} + +// Path returns the original path of the installed skill file. +func (e *InstalledSkill) Path() string { + return e.path +} + +// ResolvePath follows any symlinks and returns the absolute path of the ultimate target file. +func (e *InstalledSkill) ResolvePath() (string, error) { + if e.path == "" { + return "", fmt.Errorf("path is empty") + } + + evaled, err := filepath.EvalSymlinks(e.path) + if err != nil { + return "", err + } + return filepath.Abs(evaled) +} + +// ReinstallCommand returns the command to reinstall the existing skill. +func (e *InstalledSkill) ReinstallCommand() string { + if e.global { + return fmt.Sprintf("%s harness install --global %s", version.Name, e.agentName) + } + return fmt.Sprintf("%s harness install %s", version.Name, e.agentName) +} + +// sha256AtPath calculates and returns the SHA256 hash of the file at path. +// Returns an empty string if the file cannot be read or the hash cannot be calculated. +func sha256AtPath(path string) string { + f, err := os.Open(path) + if err == nil { + defer f.Close() + if hash, err := hashSHA256Hex(f); err == nil { + return hash + } + } + return "" +} + +// KnownSkillMatch contains information about a known version of an installed skill. +type KnownSkillMatch struct { + Version string + Hash string +} + +// MatchesKnownVersion checks if the existing skill is from a known version. +func (e *InstalledSkill) MatchesKnownVersion() (*KnownSkillMatch, bool) { + return matchesKnownVersionAtPath(e.Path()) +} + +func matchesKnownVersionAtPath(path string) (*KnownSkillMatch, bool) { + hash := sha256AtPath(path) + if hash == "" { + return nil, false + } + + hashes, err := FS.Open(TFCTLKnownHashesPath) + if err != nil { + return nil, false + } + defer hashes.Close() + + scanner := bufio.NewScanner(hashes) + for scanner.Scan() { + line := scanner.Text() + if line == "" || strings.HasPrefix(line, "#") { + continue + } + + fields := strings.Split(line, " ") + + if len(fields) != 2 { + continue + } + + if hash == fields[0] { + return &KnownSkillMatch{ + Version: fields[1], + Hash: fields[0], + }, true + } + } + // Ignore + _ = scanner.Err() + + return nil, false +} + +func hashSHA256Hex(r io.Reader) (string, error) { + hasher := sha256.New() + if _, err := io.Copy(hasher, r); err != nil { + return "", err + } + return hex.EncodeToString(hasher.Sum(nil)), nil +} diff --git a/skills/existing_test.go b/skills/existing_test.go new file mode 100644 index 0000000..4459664 --- /dev/null +++ b/skills/existing_test.go @@ -0,0 +1,132 @@ +// Copyright IBM Corp. 2026 +// SPDX-License-Identifier: MPL-2.0 + +package skills + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestInstalledSkill_ReinstallCommand(t *testing.T) { + cases := []struct { + name string + global bool + agentName string + expected string + }{ + { + name: "global", + global: true, + agentName: "opencode", + expected: "tfctl harness install --global opencode", + }, + { + name: "local", + global: false, + agentName: "opencode", + expected: "tfctl harness install opencode", + }, + { + name: "global claude", + global: true, + agentName: "claude", + expected: "tfctl harness install --global claude", + }, + { + name: "local claude", + global: false, + agentName: "claude", + expected: "tfctl harness install claude", + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + s := &InstalledSkill{ + path: "/some/path/SKILL.md", + global: c.global, + agentName: c.agentName, + } + require.Equal(t, c.expected, s.ReinstallCommand()) + }) + } +} + +func copyFile(src, dst string) error { + input, err := os.ReadFile(src) + if err != nil { + return err + } + return os.WriteFile(dst, input, 0644) +} + +func TestInstalledSkill_KnownVersion(t *testing.T) { + t.Run("matches embedded hash", func(t *testing.T) { + dir := t.TempDir() + dst := filepath.Join(dir, "SKILL.md") + require.NoError(t, copyFile(filepath.Join("fixtures", "0_3_0.md"), dst)) + + s := &InstalledSkill{path: dst} + ver, ok := s.MatchesKnownVersion() + if ok { + require.NotEmpty(t, ver) + } + require.Equal(t, ver.Version, "v0.3.0") + }) + + t.Run("unknown content returns no match", func(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "SKILL.md") + require.NoError(t, os.WriteFile(path, []byte("unknown content that won't match any hash"), 0644)) + + s := &InstalledSkill{path: path} + version, ok := s.MatchesKnownVersion() + require.False(t, ok) + require.Empty(t, version) + }) + + t.Run("missing file returns no match", func(t *testing.T) { + s := &InstalledSkill{path: "/nonexistent/path/SKILL.md"} + version, ok := s.MatchesKnownVersion() + require.False(t, ok) + require.Empty(t, version) + }) + + t.Run("empty file returns no match", func(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "SKILL.md") + require.NoError(t, os.WriteFile(path, []byte{}, 0644)) + + s := &InstalledSkill{path: path} + version, ok := s.MatchesKnownVersion() + require.False(t, ok) + require.Empty(t, version) + }) +} + +func TestMatchesKnownVersionAtPath_UsesResolvedPath(t *testing.T) { + dir := t.TempDir() + knownPath := filepath.Join(dir, "known.md") + unknownPath := filepath.Join(dir, "unknown.md") + linkPath := filepath.Join(dir, "SKILL.md") + + require.NoError(t, copyFile(filepath.Join("fixtures", "0_3_0.md"), knownPath)) + require.NoError(t, os.WriteFile(unknownPath, []byte("user-edited content"), 0644)) + require.NoError(t, os.Symlink(knownPath, linkPath)) + + skill := &InstalledSkill{path: linkPath} + resolvedPath, err := skill.ResolvePath() + require.NoError(t, err) + + // Simulate the original symlink changing after migration resolves its target. + require.NoError(t, os.Remove(linkPath)) + require.NoError(t, os.Symlink(unknownPath, linkPath)) + + match, ok := matchesKnownVersionAtPath(resolvedPath) + require.True(t, ok) + require.Equal(t, "v0.3.0", match.Version) +} diff --git a/skills/fixtures/0_3_0.md b/skills/fixtures/0_3_0.md new file mode 100644 index 0000000..38af01c --- /dev/null +++ b/skills/fixtures/0_3_0.md @@ -0,0 +1,191 @@ +--- +name: tfctl +description: | + Interact with HCP Terraform / Terraform Cloud using the tfctl CLI. Full API coverage. + Use for ANY HCP Terraform or Terraform Cloud question or action — listing workspaces, + starting/diagnosing runs, reading vars, modifying resources, calling API operations. +license: MPL-2.0 +--- + +# tfctl — HCP Terraform CLI + +Single binary, full v2 API coverage. Already authenticated. + +## Hard rules + +1. **Never pipe `tfctl` JSON to an external `jq`.** Use the built-in `--jq ''` flag — it implies `--json` and runs gojq on the response envelope. +2. **Never issue `-X DELETE`.** All deletes need a human. If asked to delete, print the exact command and ask the user to run it. +3. **Resolve names with `-p`, not separate lookup calls.** Paths with `{workspace}`/`{team}`/`{project}`/`{varset}` accept `-p workspace=NAME` etc. — tfctl resolves name→ID for you. Don't fetch the ID first. +4. **Trust the first answer.** `data: []`, `data: null`, `relationships.X.data: null`, or stderr "no current run"/"not found" ARE the answer. Don't re-query in another format. Don't walk relationships "to verify". +5. **When a named resource is not found, stop completely.** Exit code 2 or absence from a listing IS the full answer. Never: + - Try a different resource ID "to verify the endpoint works" + - Pivot to another org/workspace that appeared in the available list + - Explore related resources to find "similar" information + - Use Rule 4 to justify switching to a different resource: if you listed orgs and 'platform' isn't there, the first answer is "platform doesn't exist" — stop, don't use whatever org IS listed instead. + + Examples: `run-POLICY` returns exit 2 → stop, don't query other run IDs. Listing orgs shows no 'platform' → stop, don't use the org that IS listed. + +### URL shape: per-workspace subpaths live at `/workspaces/{workspace}/...` + +Most "things attached to a workspace" (vars, runs, varsets, remote-state-consumers, configuration-versions, notification-configurations, state-versions) are under `/workspaces/{workspace}/...`, NOT `/organizations/{org}/workspaces/{name}/...`. The org-nested form only exists for the workspace resource itself (`/organizations/{org}/workspaces/{name}`). For everything else, use `/workspaces/{workspace}/X -p workspace=NAME`. + +**Exception: Policy checks and run-specific data** live under `/runs/{run-id}/...`, not under workspace paths. For example: `/runs/{run-id}/policy-checks`. + +### Anti-patterns to avoid + +These paths **do not exist**; don't try them: +- ❌ `/organizations/{org}/workspaces/{name}/vars` — use `/workspaces/{workspace}/vars -p workspace=NAME` instead +- ❌ `/organizations/{org}/workspaces/{name}/state-versions` — use `/workspaces/{workspace}/state-versions -p workspace=NAME` +- ❌ `/organizations/{org}/workspaces/{name}/configuration-versions` — use `/workspaces/{workspace}/configuration-versions -p workspace=NAME` +- ❌ `/workspaces/{workspace}/policy-checks` — use `/runs/{run-id}/policy-checks` instead +- ❌ `/organizations/{org}/varsets` (partially wrong path) — use `/organizations/{organization}/varsets` with correct org placeholder +- ❌ External `jq` pipes like `tfctl ... | jq '...'` — always use `tfctl api ... --jq '...'` with built-in flag + +## Cookbook — one-line answers for common tasks + +```bash +# Count workspaces in an org +tfctl api /organizations/{organization}/workspaces --page-size 1 --jq '.meta.pagination.["total-count"]' + +# Find workspace by partial name (server-side search) — also returns current run state in one call +tfctl api /organizations/{organization}/workspaces -f 'search[name]=TERM' --jq '.data[] | {id, name: .attributes.name, current_run: .relationships.["current-run"].data}' + +# Filter workspaces by attribute +tfctl api /organizations/{organization}/workspaces --all --jq '.data[] | select(.attributes.["terraform-version"] | startswith("1.8")) | .attributes.name' + +# List variables on a workspace — path is /workspaces/{workspace}/vars (NOT /organizations/{org}/workspaces/{name}/vars; that endpoint does not exist) +tfctl api /workspaces/{workspace}/vars -p workspace=NAME --jq '.data[] | {key: .attributes.key, category: .attributes.category, sensitive: .attributes.sensitive}' + +# Get current run status +tfctl run status NAME_OR_ID # If it prints "no current run" or exits non-zero with that message, that IS the answer. + +# Get current run ID for a workspace +tfctl api /organizations/{organization}/workspaces/NAME --jq '.data.relationships.["current-run"].data.id' + +# List runs in a workspace with status filtering +tfctl api /workspaces/{workspace}/runs -p workspace=NAME --jq '.data[] | select(.attributes.status == "planned") | {id, status: .attributes.status}' + +# Find workspace by VCS repo identifier (single call; no results = not connected to that repo) +tfctl api /organizations/{organization}/workspaces --all \ + --jq '.data[] | select(.attributes.["vcs-repo"] != null and .attributes.["vcs-repo"].identifier == "org/repo") | {id: .id, name: .attributes.name}' + +# List workspaces accessible to a team (two-step: resolve team name → query team-workspaces) +# Note: /organizations/{org}/teams/{id}/workspaces does NOT exist — use /team-workspaces instead +tfctl api /organizations/{organization}/teams -f 'filter[names]=TEAM_NAME' --jq '.data[0].id' +tfctl api /team-workspaces -f 'filter[team][id]=TEAM_ID' --jq '.data[] | {workspace_id: .relationships.workspace.data.id, access: .attributes.access}' + +# Get organization details and settings +tfctl api /organizations/{organization} --jq '.data | {id, name: .attributes.name, created_at: .attributes."created-at", terraform_version_default: .attributes."terraform-version"}' + +# Get the current state version for a workspace +# (operationId: getCurrentStateVersion — single resource, not a list) +tfctl api /workspaces/{workspace}/current-state-version -p workspace=NAME --jq '.data | {serial: .attributes.serial, created_at: .attributes.["created-at"], status: .attributes.status}' + +# List all variable sets in an org and their variable counts +tfctl api /organizations/{organization}/varsets --all --jq '.data[] | {name: .attributes.name, id: .id, var_count: (.relationships.vars.data | length)}' + +# Get configuration version details +tfctl api /workspaces/{workspace}/configuration-versions -p workspace=NAME --jq '.data[] | {id, source: .attributes.source, created_at: .attributes.created-at}' + +# List notification configurations +tfctl api /workspaces/{workspace}/notification-configurations -p workspace=NAME --jq '.data[] | {id, type: .attributes.destination-type, trigger: .attributes.triggers}' + +# Filter workspaces by terraform version (1.7+) +tfctl api /organizations/{organization}/workspaces --all --jq '.data[] | select(.attributes.["terraform-version"] | ltrimstr("v") | split(".") | [.[0], .[1]] | join(".") | tonumber >= 1.7) | {name: .attributes.name, tf_version: .attributes.["terraform-version"]}' + +# Filter workspaces excluding certain names +tfctl api /organizations/{organization}/workspaces --all --jq '.data[] | select(.attributes.name | test("^temp-|^old-") | not) | .attributes.name' + +# Count resources by status (e.g., runs by status) +tfctl api /workspaces/{workspace}/runs -p workspace=NAME --all --jq '[.data[] | .attributes.status] | group_by(.) | map({status: .[0], count: length})' + +# Get log URL for a completed run +# Note: run.log-read-url is null on completed runs — the URL lives on plan/apply. +tfctl api /runs/RUN_ID --jq '.data.relationships | {plan: .plan.data.id, apply: .apply.data.id}' +tfctl api /plans/PLAN_ID --jq '.data.attributes.["log-read-url"]' + +# Start a run +tfctl run start NAME_OR_ID + +# Add a remote state consumer to a workspace +# (operationId: addWorkspaceRemoteStateConsumers — POST returns 204) +tfctl api /workspaces/{workspace}/relationships/remote-state-consumers -p workspace=NAME \ + -i '{"data":[{"type":"workspaces","id":"ws-CONSUMER_ID"}]}' + +# Apply a variable set to a workspace +# (operationId: updateWorkspaceRelationship for varsets) +tfctl api /workspaces/{workspace}/relationships/varsets -p workspace=NAME \ + -X POST -i '{"data":[{"type":"varsets","id":"varset-VARSET_ID"}]}' + +# Get policy check results for a run +tfctl api /runs/{run-id}/policy-checks --jq '.data[] | {id: .id, status: .attributes.status, enforced: .attributes.enforcement-level}' + +# Discover an API operation when you don't know it +tfctl api schema search "KEYWORD" --json # returns operationIds +tfctl api schema get OPERATION_ID # full OpenAPI schema (large response — only call when needed) +``` + +## Output flags + +| Need | Flag | +|-------------------|------------------| +| Filter / extract | `--jq ''` | +| Full JSON | `--json` | +| Render for human | `--markdown` | +| Audit a mutation | `--dry-run` | + +`--jq` implies `--json`. Don't pass both. Always pass one explicitly — don't rely on auto-detect. + +## JSON:API conventions + +Responses are JSON:API envelopes: `{data: {id, type, attributes, relationships}}` (or `data: [...]` for lists). To follow a link, read `data.relationships..data` which gives `{id, type}` or `null`. A `null` is final — there is no related resource. + +Pagination: default page 1. Add `--all` for all pages (cap 2000), or `--page-size N` / `--page-number N` for explicit control. For counts, use `--page-size 1 --jq '.meta.pagination.["total-count"]'`. + +## Mutations & batch updates + +```bash +# Create or update a single variable +tfctl api /workspaces/{workspace}/vars -p workspace=NAME -a key=VARKEY -a value=VALUE -a category=env + +# Batch updates: use separate calls (HCP TFC doesn't support bulk POST for vars) +# Instead of trying /workspaces/{ws}/vars with multiple items, do: +tfctl api /workspaces/{workspace}/vars -p workspace=NAME -a key=VAR1 -a value=VAL1 -a category=env +tfctl api /workspaces/{workspace}/vars -p workspace=NAME -a key=VAR2 -a value=VAL2 -a category=env +# (Multiple calls cost more, but it's the supported pattern) + +# PATCH with a raw body +tfctl api /workspaces/{workspace}/X -X PATCH -p workspace=NAME -i '{"data":{"type":"X","attributes":{…}}}' +``` +Add `--dry-run` to preview without sending. + +## Exit codes (quick map) + +| Code | Meaning | Action | +|------|---------|--------| +| 0 | Success | Done | +| 1 | Informational message or usage error | Read stderr; if it says "no current run" or similar, **that IS the answer — stop** | +| 2 | Not found (workspace/run doesn't exist) OR invalid auth | Verify the ID/name is correct, then check token if still failing | +| 3 | Auth token expired or invalid | Re-authenticate | +| 4 | Network error | Retry after brief delay | +| 5 | Rate limited (429) or server error (5xx) | Retry with backoff | +| 6 | Resource has an error state | The error is already diagnosed in output (e.g., plan failed); read it | + +**Important**: When an API returns `data: []` (empty list) or `data: null`, that IS the answer. Don't retry with different flags or endpoints. + +### Common troubleshooting + +| Symptom | Cause | Fix | +|---------|-------|-----| +| `exit 2` when listing workspaces | Organization doesn't exist or auth token has no access | Verify org name and re-authenticate | +| `exit 1` with "no current run" | Workspace simply has no active run (informational) | **This is the answer** — stop, don't verify | +| `exit 3` when making any API call | Auth token expired | Re-authenticate with `tfctl login` | +| `exit 5` (429 rate limit) | Too many requests | Wait and retry; tfctl will backoff automatically | +| `exit 6` with "plan is errored" | Terraform plan had syntax errors (not CLI error) | Read the plan output for details | +| Empty list (`data: []`) when filtering | No resources match criteria | Verify criteria is correct; empty list is valid answer | + +## Smart defaults + +- `{organization}` resolves from active profile if set. +- `{workspace}` resolves from a local `cloud {}` block in CWD. +- Already-formed IDs (`ws-…`, `team-…`, `prj-…`, `varset-…`) are passed through as-is. diff --git a/skills/install.go b/skills/install.go index 7278a20..bd1b9af 100644 --- a/skills/install.go +++ b/skills/install.go @@ -6,11 +6,14 @@ package skills import ( "fmt" "io" + "iter" "os" "path/filepath" "slices" "github.com/mitchellh/go-homedir" + + "github.com/hashicorp/tfctl-cli/version" ) // AgentSpec defines the necessary information to install a skill for a coding agent. @@ -19,7 +22,7 @@ type AgentSpec struct { DisplayName string SkillsDir string GlobalSkillsDir func() string - Detect func() bool + DetectInstalled func() bool DetectParentProcess func() bool } @@ -32,13 +35,19 @@ func detectHomeDirPath(dir string) bool { return err == nil } -// TFCTLSkillPath is the path to the embedded SKILL.md file within the binary. -const TFCTLSkillPath = "tfctl/SKILL.md" +const ( + // TFCTLSkillPath is the path to the embedded SKILL.md file within the binary. + TFCTLSkillPath = "tfctl/SKILL.md" + // TFCTLKnownHashesPath is the path to the embedded hashes file within the binary. + TFCTLKnownHashesPath = "tfctl/known_release_hashes" +) -var agents map[string]AgentSpec +var ( + agents map[string]AgentSpec -// AgentNames is a list of the names of all supported agents. -var AgentNames []string + // AgentNames is a list of the names of all supported agents. + AgentNames []string +) func init() { agents = registerAgents() @@ -73,7 +82,7 @@ func registerAgents() map[string]AgentSpec { path, _ := homedir.Expand("~/.config/agents/skills") return path }, - Detect: func() bool { + DetectInstalled: func() bool { return detectHomeDirPath(".config/amp") }, DetectParentProcess: func() bool { @@ -88,7 +97,7 @@ func registerAgents() map[string]AgentSpec { path, _ := homedir.Expand("~/.gemini/config/skills") return path }, - Detect: func() bool { + DetectInstalled: func() bool { return detectHomeDirPath(".gemini") }, DetectParentProcess: func() bool { @@ -104,7 +113,7 @@ func registerAgents() map[string]AgentSpec { path, _ := homedir.Expand("~/.bob/skills") return path }, - Detect: func() bool { + DetectInstalled: func() bool { return detectHomeDirPath(".bob") }, DetectParentProcess: func() bool { @@ -119,7 +128,7 @@ func registerAgents() map[string]AgentSpec { GlobalSkillsDir: func() string { return filepath.Join(claudeDir, "skills") }, - Detect: func() bool { + DetectInstalled: func() bool { _, err := os.Stat(claudeDir) return err == nil }, @@ -134,7 +143,7 @@ func registerAgents() map[string]AgentSpec { GlobalSkillsDir: func() string { return filepath.Join(codexDir, "skills") }, - Detect: func() bool { + DetectInstalled: func() bool { _, err := os.Stat(codexDir) return err == nil }, @@ -151,7 +160,7 @@ func registerAgents() map[string]AgentSpec { path, _ := homedir.Expand("~/.copilot/skills") return path }, - Detect: func() bool { + DetectInstalled: func() bool { return detectHomeDirPath(".copilot") }, DetectParentProcess: func() bool { @@ -166,7 +175,7 @@ func registerAgents() map[string]AgentSpec { path, _ := homedir.Expand("~/.config/opencode/skills") return path }, - Detect: func() bool { + DetectInstalled: func() bool { return detectHomeDirPath(".config/opencode") }, DetectParentProcess: func() bool { @@ -181,7 +190,7 @@ func registerAgents() map[string]AgentSpec { path, _ := homedir.Expand("~/.pi/agent/skills") return path }, - Detect: func() bool { + DetectInstalled: func() bool { return detectHomeDirPath(".pi") }, DetectParentProcess: func() bool { @@ -191,6 +200,63 @@ func registerAgents() map[string]AgentSpec { } } +// DetectAnyExistingSkill checks returns the first existing skill it finds from any known +// agent, starting with locally install skills, or nil if none are found. +func DetectAnyExistingSkill() *InstalledSkill { + for _, name := range AgentNames { + if agent, ok := GetAgent(name); ok { + if s := agent.DetectLocallyInstalledSkill(); s != nil { + return s + } + } + } + for _, name := range AgentNames { + if agent, ok := GetAgent(name); ok { + if s := agent.DetectGloballyInstalledSkill(); s != nil { + return s + } + } + } + return nil +} + +// DetectLocallyInstalledSkill checks if the tfctl skill already exists for the agent in the +// local project directory, and returns an InstalledSkill if found. +func (a *AgentSpec) DetectLocallyInstalledSkill() *InstalledSkill { + skillPath := filepath.Join(a.SkillsDir, TFCTLSkillPath) + if s, err := os.Stat(skillPath); err == nil && !s.IsDir() { + return &InstalledSkill{path: skillPath, global: false, agentName: a.Name} + } + return nil +} + +// DetectGloballyInstalledSkill checks if the tfctl skill already exists for the agent in the +// global config directory, and returns an InstalledSkill if found. +func (a *AgentSpec) DetectGloballyInstalledSkill() *InstalledSkill { + globalSkillPath := filepath.Join(a.GlobalSkillsDir(), TFCTLSkillPath) + if s, err := os.Stat(globalSkillPath); err == nil && !s.IsDir() { + return &InstalledSkill{path: globalSkillPath, global: true, agentName: a.Name} + } + return nil +} + +// InstalledSkills returns a sequence of both/either/neither installed skills for the agent. +// First local, then global. +func (a *AgentSpec) InstalledSkills() iter.Seq[*InstalledSkill] { + return func(yield func(*InstalledSkill) bool) { + if s := a.DetectLocallyInstalledSkill(); s != nil { + if !yield(s) { + return + } + } + if s := a.DetectGloballyInstalledSkill(); s != nil { + if !yield(s) { + return + } + } + } +} + // GetAgent returns the AgentSpec for a given agent name, along with a boolean indicating whether // the agent was found. func GetAgent(name string) (AgentSpec, bool) { @@ -198,11 +264,21 @@ func GetAgent(name string) (AgentSpec, bool) { return agent, ok } -// DetectAgent returns a list of AgentSpecs for agents detected on the current system. -func DetectAgent() []AgentSpec { +// DetectAgent returns the first AgentSpec for any agent detected on the current system. +func DetectAgent() (AgentSpec, bool) { + for _, agent := range agents { + if agent.DetectInstalled() { + return agent, true + } + } + return AgentSpec{}, false +} + +// DetectAgents returns a list of AgentSpecs for agents detected on the current system. +func DetectAgents() []AgentSpec { var detected []AgentSpec for _, agent := range agents { - if agent.Detect() { + if agent.DetectInstalled() { detected = append(detected, agent) } } @@ -210,15 +286,7 @@ func DetectAgent() []AgentSpec { return detected } -// InstallSkill installs the tfctl skill for the agent, either to the project directory or the -// global config directory based on the value of the global parameter. -func (a AgentSpec) InstallSkill(global bool) error { - file, err := FS.Open(TFCTLSkillPath) - if err != nil { - return fmt.Errorf("failed to open embedded SKILL.md file: %w", err) - } - defer file.Close() - +func (a AgentSpec) skillFilePath(global bool) (string, error) { targetDir := a.SkillsDir if global { targetDir = a.GlobalSkillsDir() @@ -227,19 +295,51 @@ func (a AgentSpec) InstallSkill(global bool) error { targetDir = filepath.Join(targetDir, "tfctl") if err := os.MkdirAll(targetDir, 0755); err != nil { - return fmt.Errorf("failed to create target directory %q: %w", targetDir, err) + return "", fmt.Errorf("failed to create target directory %q: %w", targetDir, err) } - targetPath := fmt.Sprintf("%s/SKILL.md", targetDir) - targetFile, err := os.Create(targetPath) + return fmt.Sprintf("%s/SKILL.md", targetDir), nil +} + +// installSkillToPath installs the tfctl skill for the agent to a specific file path. +func (a AgentSpec) installSkillToPath(path string) error { + file, err := FS.Open(TFCTLSkillPath) if err != nil { - return fmt.Errorf("failed to create target file %q: %w", targetPath, err) + return fmt.Errorf("failed to open embedded SKILL.md file: %w", err) } - defer targetFile.Close() + defer file.Close() - _, err = io.Copy(targetFile, file) + tempFile, err := os.CreateTemp(filepath.Dir(path), fmt.Sprintf("SKILL-%s-*", version.Name)) if err != nil { - return fmt.Errorf("failed to copy skill file to target location: %w", err) + return fmt.Errorf("failed to create temporary file: %w", err) + } + defer os.Remove(tempFile.Name()) + + _, err = io.Copy(tempFile, file) + if err != nil { + return fmt.Errorf("failed to write temporary file: %w", err) + } + err = tempFile.Sync() + if err != nil { + return fmt.Errorf("failed to sync temporary file: %w", err) + } + err = tempFile.Close() + if err != nil { + return fmt.Errorf("failed to close temporary file: %w", err) + } + + if err := os.Rename(tempFile.Name(), path); err != nil { + return fmt.Errorf("failed to install to target path: %w", err) } return nil } + +// InstallSkill installs the tfctl skill for the agent, either to the project directory or the +// global config directory based on the value of the global parameter. +func (a AgentSpec) InstallSkill(global bool) error { + targetPath, err := a.skillFilePath(global) + if err != nil { + return err + } + return a.installSkillToPath(targetPath) +} diff --git a/skills/install_test.go b/skills/install_test.go index c224ffc..a17ed45 100644 --- a/skills/install_test.go +++ b/skills/install_test.go @@ -5,6 +5,8 @@ package skills import ( "os" + "path/filepath" + "slices" "testing" "github.com/mitchellh/go-homedir" @@ -15,23 +17,28 @@ func TestInstallSkill(t *testing.T) { cases := []struct { agentName string expectedGlobalInstall string + expectedLocalInstall string setup func(t *testing.T) }{ { - agentName: "bob", - expectedGlobalInstall: "~/.bob/skills/tfctl/SKILL.md", + agentName: "amp", + expectedGlobalInstall: "~/.config/agents/skills/tfctl/SKILL.md", + expectedLocalInstall: ".agents/skills/tfctl/SKILL.md", }, { - agentName: "codex", - expectedGlobalInstall: "~/.codex/skills/tfctl/SKILL.md", + agentName: "antigravity", + expectedGlobalInstall: "~/.gemini/config/skills/tfctl/SKILL.md", + expectedLocalInstall: ".agents/skills/tfctl/SKILL.md", }, { - agentName: "opencode", - expectedGlobalInstall: "~/.config/opencode/skills/tfctl/SKILL.md", + agentName: "bob", + expectedGlobalInstall: "~/.bob/skills/tfctl/SKILL.md", + expectedLocalInstall: ".bob/skills/tfctl/SKILL.md", }, { agentName: "claude", expectedGlobalInstall: "~/CustomClaudeDir/skills/tfctl/SKILL.md", + expectedLocalInstall: ".claude/skills/tfctl/SKILL.md", setup: func(t *testing.T) { t.Helper() customDir, err := homedir.Expand("~/CustomClaudeDir") @@ -49,6 +56,26 @@ func TestInstallSkill(t *testing.T) { }) }, }, + { + agentName: "codex", + expectedGlobalInstall: "~/.codex/skills/tfctl/SKILL.md", + expectedLocalInstall: ".codex/skills/tfctl/SKILL.md", + }, + { + agentName: "copilot", + expectedGlobalInstall: "~/.copilot/skills/tfctl/SKILL.md", + expectedLocalInstall: ".agents/skills/tfctl/SKILL.md", + }, + { + agentName: "opencode", + expectedGlobalInstall: "~/.config/opencode/skills/tfctl/SKILL.md", + expectedLocalInstall: ".agents/skills/tfctl/SKILL.md", + }, + { + agentName: "pi", + expectedGlobalInstall: "~/.pi/agent/skills/tfctl/SKILL.md", + expectedLocalInstall: ".agents/skills/tfctl/SKILL.md", + }, } for _, c := range cases { @@ -78,12 +105,29 @@ func TestInstallSkill(t *testing.T) { expected, err := homedir.Expand(c.expectedGlobalInstall) require.NoError(t, err) require.FileExists(t, expected) + + installed := agent.DetectGloballyInstalledSkill() + require.NotNil(t, installed) + require.Equal(t, expected, installed.Path()) + + if c.expectedLocalInstall != "" { + tmpLocal := t.TempDir() + t.Chdir(tmpLocal) + err := agent.InstallSkill(false) + require.NoError(t, err) + + require.FileExists(t, c.expectedLocalInstall) + + installedLocal := agent.DetectLocallyInstalledSkill() + require.NotNil(t, installedLocal) + require.Equal(t, c.expectedLocalInstall, installedLocal.Path()) + } }) } // Make sure every agent has some basic fields defined for _, agent := range agents { - agent.Detect() + agent.DetectInstalled() agent.DetectParentProcess() require.NotEmpty(t, agent.Name) require.NotEmpty(t, agent.DisplayName) @@ -91,3 +135,555 @@ func TestInstallSkill(t *testing.T) { require.NotEmpty(t, agent.GlobalSkillsDir()) } } + +func TestInstalledSkill_ResolvePath(t *testing.T) { + t.Run("returns absolute path for regular file", func(t *testing.T) { + tmpDir := t.TempDir() + filePath := filepath.Join(tmpDir, "tfctl", "SKILL.md") + require.NoError(t, os.MkdirAll(filepath.Dir(filePath), 0755)) + require.NoError(t, os.WriteFile(filePath, []byte("test"), 0644)) + + skill := &InstalledSkill{path: filePath, global: false, agentName: "pi"} + resolved, err := skill.ResolvePath() + require.NoError(t, err) + expected, err := filepath.EvalSymlinks(filePath) + require.NoError(t, err) + require.Equal(t, expected, resolved) + }) + + t.Run("follows symlink to target", func(t *testing.T) { + tmpDir := t.TempDir() + realFile := filepath.Join(tmpDir, "real_skill.md") + require.NoError(t, os.WriteFile(realFile, []byte("test"), 0644)) + + linkPath := filepath.Join(tmpDir, "linked_skill.md") + require.NoError(t, os.Symlink(realFile, linkPath)) + + skill := &InstalledSkill{path: linkPath, global: false, agentName: "pi"} + resolved, err := skill.ResolvePath() + require.NoError(t, err) + expected, err := filepath.EvalSymlinks(realFile) + require.NoError(t, err) + require.Equal(t, expected, resolved) + }) + + t.Run("follows symlink with relative target", func(t *testing.T) { + tmpDir := t.TempDir() + realFile := filepath.Join(tmpDir, "real_skill.md") + require.NoError(t, os.WriteFile(realFile, []byte("test"), 0644)) + + linkPath := filepath.Join(tmpDir, "linked_skill.md") + require.NoError(t, os.Symlink("real_skill.md", linkPath)) + + oldWd, _ := os.Getwd() + os.Chdir(tmpDir) + t.Cleanup(func() { os.Chdir(oldWd) }) + + skill := &InstalledSkill{path: linkPath, global: false, agentName: "pi"} + resolved, err := skill.ResolvePath() + require.NoError(t, err) + // resolved should point to the real file (basename match, since /var -> /private/var on macOS) + require.Equal(t, "real_skill.md", filepath.Base(resolved)) + // verify the resolved path actually points to the real file + resolvedAbs, err := filepath.EvalSymlinks(resolved) + require.NoError(t, err) + realAbs, err := filepath.EvalSymlinks(realFile) + require.NoError(t, err) + require.Equal(t, realAbs, resolvedAbs) + }) + + t.Run("follows nested symlinks", func(t *testing.T) { + tmpDir := t.TempDir() + realFile := filepath.Join(tmpDir, "real_skill.md") + require.NoError(t, os.WriteFile(realFile, []byte("test"), 0644)) + + secondLink := filepath.Join(tmpDir, "second_link.md") + require.NoError(t, os.Symlink("real_skill.md", secondLink)) + firstLink := filepath.Join(tmpDir, "first_link.md") + require.NoError(t, os.Symlink("second_link.md", firstLink)) + + skill := &InstalledSkill{path: firstLink, global: false, agentName: "pi"} + resolved, err := skill.ResolvePath() + require.NoError(t, err) + expected, err := filepath.EvalSymlinks(realFile) + require.NoError(t, err) + require.Equal(t, expected, resolved) + }) + + t.Run("returns error for empty path", func(t *testing.T) { + skill := &InstalledSkill{path: "", global: false, agentName: "pi"} + _, err := skill.ResolvePath() + require.Error(t, err) + require.Contains(t, err.Error(), "path is empty") + }) + + t.Run("returns error for non-existent path", func(t *testing.T) { + skill := &InstalledSkill{path: "/nonexistent/path/SKILL.md", global: false, agentName: "pi"} + _, err := skill.ResolvePath() + require.Error(t, err) + }) +} + +func TestAgentSpec_InstalledSkills(t *testing.T) { + t.Run("returns both local and global skills", func(t *testing.T) { + tmpDir := t.TempDir() + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + agents = registerAgents() + agent, ok := GetAgent("pi") + require.True(t, ok) + + // Create local skill + localPath := filepath.Join(tmpDir, agent.SkillsDir, TFCTLSkillPath) + require.NoError(t, os.MkdirAll(filepath.Dir(localPath), 0755)) + require.NoError(t, os.WriteFile(localPath, []byte("local"), 0644)) + + // Create global skill + globalPath := filepath.Join(agent.GlobalSkillsDir(), TFCTLSkillPath) + require.NoError(t, os.MkdirAll(filepath.Dir(globalPath), 0755)) + require.NoError(t, os.WriteFile(globalPath, []byte("global"), 0644)) + + oldWd, _ := os.Getwd() + os.Chdir(tmpDir) + t.Cleanup(func() { os.Chdir(oldWd) }) + + var collected []*InstalledSkill + for s := range agent.InstalledSkills() { + collected = append(collected, s) + } + + require.Len(t, collected, 2) + require.Equal(t, filepath.Join(agent.SkillsDir, TFCTLSkillPath), collected[0].Path()) + require.False(t, collected[0].global) + require.Equal(t, globalPath, collected[1].Path()) + require.True(t, collected[1].global) + }) + + t.Run("returns only local skill when global does not exist", func(t *testing.T) { + tmpDir := t.TempDir() + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + agents = registerAgents() + agent, ok := GetAgent("pi") + require.True(t, ok) + + localPath := filepath.Join(tmpDir, agent.SkillsDir, TFCTLSkillPath) + require.NoError(t, os.MkdirAll(filepath.Dir(localPath), 0755)) + require.NoError(t, os.WriteFile(localPath, []byte("local"), 0644)) + + oldWd, _ := os.Getwd() + os.Chdir(tmpDir) + t.Cleanup(func() { os.Chdir(oldWd) }) + + var collected []*InstalledSkill + for s := range agent.InstalledSkills() { + collected = append(collected, s) + } + + require.Len(t, collected, 1) + require.Equal(t, filepath.Join(agent.SkillsDir, TFCTLSkillPath), collected[0].Path()) + require.False(t, collected[0].global) + }) + + t.Run("returns only global skill when local does not exist", func(t *testing.T) { + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + agents = registerAgents() + agent, ok := GetAgent("pi") + require.True(t, ok) + + globalPath := filepath.Join(agent.GlobalSkillsDir(), TFCTLSkillPath) + require.NoError(t, os.MkdirAll(filepath.Dir(globalPath), 0755)) + require.NoError(t, os.WriteFile(globalPath, []byte("global"), 0644)) + + var collected []*InstalledSkill + for s := range agent.InstalledSkills() { + collected = append(collected, s) + } + + require.Len(t, collected, 1) + require.Equal(t, globalPath, collected[0].Path()) + require.True(t, collected[0].global) + }) + + t.Run("returns nothing when no skills exist", func(t *testing.T) { + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + agents = registerAgents() + agent, ok := GetAgent("pi") + require.True(t, ok) + + var collected []*InstalledSkill + for s := range agent.InstalledSkills() { + collected = append(collected, s) + } + + require.Empty(t, collected) + }) + + t.Run("skips directories with same name as skill file", func(t *testing.T) { + tmpDir := t.TempDir() + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + agents = registerAgents() + agent, ok := GetAgent("pi") + require.True(t, ok) + + // Create a directory instead of a file + dirPath := filepath.Join(tmpDir, agent.SkillsDir, "tfctl", "SKILL.md") + require.NoError(t, os.MkdirAll(dirPath, 0755)) + + oldWd, _ := os.Getwd() + os.Chdir(tmpDir) + t.Cleanup(func() { os.Chdir(oldWd) }) + + var collected []*InstalledSkill + for s := range agent.InstalledSkills() { + collected = append(collected, s) + } + + require.Empty(t, collected) + }) +} + +func TestDetectAnyExistingSkill(t *testing.T) { + t.Run("returns nil when no skills exist", func(t *testing.T) { + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + agents = registerAgents() + result := DetectAnyExistingSkill() + require.Nil(t, result) + }) + + t.Run("returns first local skill found", func(t *testing.T) { + tmpDir := t.TempDir() + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + agents = registerAgents() + + // Create a local skill for amp + ampAgent, ok := GetAgent("amp") + require.True(t, ok) + localPath := filepath.Join(tmpDir, ampAgent.SkillsDir, TFCTLSkillPath) + require.NoError(t, os.MkdirAll(filepath.Dir(localPath), 0755)) + require.NoError(t, os.WriteFile(localPath, []byte("amp skill"), 0644)) + + oldWd, _ := os.Getwd() + os.Chdir(tmpDir) + t.Cleanup(func() { os.Chdir(oldWd) }) + + result := DetectAnyExistingSkill() + require.NotNil(t, result) + require.Equal(t, "amp", result.agentName) + require.False(t, result.global) + }) + + t.Run("returns first global skill when no local skills exist", func(t *testing.T) { + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + agents = registerAgents() + + // Create a global skill for amp + ampAgent, ok := GetAgent("amp") + require.True(t, ok) + globalPath := filepath.Join(ampAgent.GlobalSkillsDir(), TFCTLSkillPath) + require.NoError(t, os.MkdirAll(filepath.Dir(globalPath), 0755)) + require.NoError(t, os.WriteFile(globalPath, []byte("amp skill"), 0644)) + + result := DetectAnyExistingSkill() + require.NotNil(t, result) + require.Equal(t, "amp", result.agentName) + require.True(t, result.global) + }) + + t.Run("prefers local over global", func(t *testing.T) { + tmpDir := t.TempDir() + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + agents = registerAgents() + + // Create both local and global skills for amp + ampAgent, ok := GetAgent("amp") + require.True(t, ok) + + localPath := filepath.Join(tmpDir, ampAgent.SkillsDir, TFCTLSkillPath) + require.NoError(t, os.MkdirAll(filepath.Dir(localPath), 0755)) + require.NoError(t, os.WriteFile(localPath, []byte("local"), 0644)) + + globalPath := filepath.Join(ampAgent.GlobalSkillsDir(), TFCTLSkillPath) + require.NoError(t, os.MkdirAll(filepath.Dir(globalPath), 0755)) + require.NoError(t, os.WriteFile(globalPath, []byte("global"), 0644)) + + oldWd, _ := os.Getwd() + os.Chdir(tmpDir) + t.Cleanup(func() { os.Chdir(oldWd) }) + + result := DetectAnyExistingSkill() + require.NotNil(t, result) + require.False(t, result.global) + require.Contains(t, result.Path(), ".agents") + }) + + t.Run("ignores directories with same name as skill file", func(t *testing.T) { + tmpDir := t.TempDir() + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + agents = registerAgents() + + ampAgent, ok := GetAgent("amp") + require.True(t, ok) + + // Create a directory instead of a file + dirPath := filepath.Join(tmpDir, ampAgent.SkillsDir, "tfctl", "SKILL.md") + require.NoError(t, os.MkdirAll(dirPath, 0755)) + + oldWd, _ := os.Getwd() + os.Chdir(tmpDir) + t.Cleanup(func() { os.Chdir(oldWd) }) + + result := DetectAnyExistingSkill() + require.Nil(t, result) + }) +} + +func TestAgentSpec_DetectLocallyInstalledSkill(t *testing.T) { + t.Run("returns nil when skill does not exist", func(t *testing.T) { + tmpDir := t.TempDir() + oldWd, _ := os.Getwd() + os.Chdir(tmpDir) + t.Cleanup(func() { os.Chdir(oldWd) }) + + agent := AgentSpec{Name: "pi", SkillsDir: ".agents/skills"} + result := agent.DetectLocallyInstalledSkill() + require.Nil(t, result) + }) + + t.Run("returns InstalledSkill when file exists", func(t *testing.T) { + tmpDir := t.TempDir() + agent := AgentSpec{Name: "pi", SkillsDir: ".agents/skills"} + localPath := filepath.Join(tmpDir, agent.SkillsDir, TFCTLSkillPath) + require.NoError(t, os.MkdirAll(filepath.Dir(localPath), 0755)) + require.NoError(t, os.WriteFile(localPath, []byte("skill content"), 0644)) + + oldWd, _ := os.Getwd() + os.Chdir(tmpDir) + t.Cleanup(func() { os.Chdir(oldWd) }) + + result := agent.DetectLocallyInstalledSkill() + require.NotNil(t, result) + require.Equal(t, filepath.Join(agent.SkillsDir, TFCTLSkillPath), result.Path()) + require.False(t, result.global) + require.Equal(t, "pi", result.agentName) + }) + + t.Run("returns nil when path is a directory", func(t *testing.T) { + tmpDir := t.TempDir() + agent := AgentSpec{Name: "pi", SkillsDir: ".agents/skills"} + dirPath := filepath.Join(tmpDir, agent.SkillsDir, "tfctl", "SKILL.md") + require.NoError(t, os.MkdirAll(dirPath, 0755)) + + oldWd, _ := os.Getwd() + os.Chdir(tmpDir) + t.Cleanup(func() { os.Chdir(oldWd) }) + + result := agent.DetectLocallyInstalledSkill() + require.Nil(t, result) + }) + + t.Run("respects agent-specific skills directory", func(t *testing.T) { + tmpDir := t.TempDir() + + // bob uses .bob/skills + agent := AgentSpec{Name: "bob", SkillsDir: ".bob/skills"} + localPath := filepath.Join(tmpDir, agent.SkillsDir, TFCTLSkillPath) + require.NoError(t, os.MkdirAll(filepath.Dir(localPath), 0755)) + require.NoError(t, os.WriteFile(localPath, []byte("skill content"), 0644)) + + oldWd, _ := os.Getwd() + os.Chdir(tmpDir) + t.Cleanup(func() { os.Chdir(oldWd) }) + + result := agent.DetectLocallyInstalledSkill() + require.NotNil(t, result) + require.Contains(t, result.Path(), ".bob/skills") + }) +} + +func TestAgentSpec_DetectGloballyInstalledSkill(t *testing.T) { + t.Run("returns nil when global skill does not exist", func(t *testing.T) { + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + agent := AgentSpec{ + Name: "pi", + SkillsDir: ".agents/skills", + GlobalSkillsDir: func() string { return filepath.Join(tmpHome, ".pi/agent/skills") }, + } + result := agent.DetectGloballyInstalledSkill() + require.Nil(t, result) + }) + + t.Run("returns InstalledSkill when global file exists", func(t *testing.T) { + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + globalSkillsDir := filepath.Join(tmpHome, ".pi/agent/skills") + agent := AgentSpec{ + Name: "pi", + SkillsDir: ".agents/skills", + GlobalSkillsDir: func() string { return globalSkillsDir }, + } + globalPath := filepath.Join(globalSkillsDir, TFCTLSkillPath) + require.NoError(t, os.MkdirAll(filepath.Dir(globalPath), 0755)) + require.NoError(t, os.WriteFile(globalPath, []byte("global skill"), 0644)) + + result := agent.DetectGloballyInstalledSkill() + require.NotNil(t, result) + require.Equal(t, globalPath, result.Path()) + require.True(t, result.global) + require.Equal(t, "pi", result.agentName) + }) + + t.Run("returns nil when path is a directory", func(t *testing.T) { + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + globalSkillsDir := filepath.Join(tmpHome, ".pi/agent/skills") + agent := AgentSpec{ + Name: "pi", + SkillsDir: ".agents/skills", + GlobalSkillsDir: func() string { return globalSkillsDir }, + } + dirPath := filepath.Join(globalSkillsDir, "tfctl", "SKILL.md") + require.NoError(t, os.MkdirAll(dirPath, 0755)) + + result := agent.DetectGloballyInstalledSkill() + require.Nil(t, result) + }) + + t.Run("respects custom global skills directory", func(t *testing.T) { + tmpHome := t.TempDir() + originalHome := os.Getenv("HOME") + os.Setenv("HOME", tmpHome) + homedir.Reset() + t.Cleanup(func() { + os.Setenv("HOME", originalHome) + homedir.Reset() + }) + + // Claude can have a custom global dir via CLAUDE_CONFIG_DIR + customDir := filepath.Join(tmpHome, "my-claude-config") + originalEnv := os.Getenv("CLAUDE_CONFIG_DIR") + os.Setenv("CLAUDE_CONFIG_DIR", customDir) + t.Cleanup(func() { + os.Setenv("CLAUDE_CONFIG_DIR", originalEnv) + }) + + agents = registerAgents() + agent, ok := GetAgent("claude") + require.True(t, ok) + + globalPath := filepath.Join(customDir, "skills", TFCTLSkillPath) + require.NoError(t, os.MkdirAll(filepath.Dir(globalPath), 0755)) + require.NoError(t, os.WriteFile(globalPath, []byte("claude skill"), 0644)) + + result := agent.DetectGloballyInstalledSkill() + require.NotNil(t, result) + require.Contains(t, result.Path(), "my-claude-config") + require.True(t, result.global) + }) + + t.Run("iterates agents in sorted order for determinism", func(t *testing.T) { + // AgentNames is sorted in init(), verify that DetectAnyExistingSkill + // finds skills in a deterministic order + require.True(t, slices.IsSorted(AgentNames)) + }) +} diff --git a/skills/migrate.go b/skills/migrate.go new file mode 100644 index 0000000..3cdd242 --- /dev/null +++ b/skills/migrate.go @@ -0,0 +1,103 @@ +package skills + +import ( + "context" + "slices" + + "github.com/hashicorp/tfctl-cli/internal/pkg/logging" + "github.com/hashicorp/tfctl-cli/version" +) + +// MigrationResult is the result of attempting to migrate an installed skill, including any +// potential failure reason, and the previous version if successful. +type MigrationResult struct { + SkillPath string + FailedReason error + PreviousVersion string +} + +// Migration represents an ongoing migration process, including a channel to signal completion +// and a slice to store results. +type Migration struct { + done chan struct{} + results []MigrationResult +} + +// StartMigration will attempt to migrate all installed skills for all agents to the +// latest known version. Call this function only once per execution. +func StartMigration(ctx context.Context) *Migration { + m := &Migration{done: make(chan struct{})} + go func() { + defer close(m.done) + m.results = migrateInstalled(ctx) + }() + return m +} + +func migrateInstalled(ctx context.Context) []MigrationResult { + logger := logging.FromContext(ctx) + seenPaths := make(map[string]struct{}) + + results := make([]MigrationResult, 0) + for _, name := range AgentNames { + if agent, ok := GetAgent(name); ok { + for existing := range agent.InstalledSkills() { + // Many agents install skills to the same path. We only need to check these once. + if _, seen := seenPaths[existing.Path()]; seen { + continue + } + seenPaths[existing.Path()] = struct{}{} + + // Some skill files are actually symlinks, so we need to resolve those first before + // overwriting the contents. + installedLocation, err := existing.ResolvePath() + if err != nil { + results = append(results, MigrationResult{ + SkillPath: existing.Path(), + FailedReason: err, + }) + continue + } + + if match, ok := matchesKnownVersionAtPath(installedLocation); ok { + if match.Hash != EmbeddedSkillHash() { + // This is a match for a previous version and can be migrated + err := agent.installSkillToPath(installedLocation) + if err != nil { + results = append(results, MigrationResult{ + SkillPath: installedLocation, + FailedReason: err, + }) + } else { + results = append(results, MigrationResult{ + SkillPath: installedLocation, + FailedReason: nil, + PreviousVersion: match.Version, + }) + } + } else { + // Matches the embedded hash. Skill is already up to date. + logger.Debug("Installed skill already up to date", "path", existing.Path()) + } + } else { + // This is not a match for any known skill and should not be migrated. + if !version.IsDev() { + logger.Debug("Installed skill is unrecognized, likely contains user edits", "path", existing.Path()) + } + } + } + } + } + return results +} + +// Wait waits for the migration process to complete and returns all MigrationResults or an error +// if the context is canceled. +func (m *Migration) Wait(ctx context.Context) ([]MigrationResult, error) { + select { + case <-m.done: + return slices.Clone(m.results), nil + case <-ctx.Done(): + return nil, context.Cause(ctx) + } +} diff --git a/skills/migrate_test.go b/skills/migrate_test.go new file mode 100644 index 0000000..ad99196 --- /dev/null +++ b/skills/migrate_test.go @@ -0,0 +1,151 @@ +// Copyright IBM Corp. 2026 +// SPDX-License-Identifier: MPL-2.0 + +package skills + +import ( + "context" + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/stretchr/testify/require" +) + +func setupMigrationTest(t *testing.T, names ...string) { + t.Helper() + + // Isolate tests from users' globally installed skills + t.Setenv("HOME", t.TempDir()) + + // Register just the named agents in the specified order + oldAgents := agents + oldAgentNames := AgentNames + agents = registerAgents() + AgentNames = names + t.Cleanup(func() { + agents = oldAgents + AgentNames = oldAgentNames + }) +} + +func writeSkill(t *testing.T, path string, contents []byte) { + t.Helper() + + require.NoError(t, os.MkdirAll(filepath.Dir(path), 0755)) + require.NoError(t, os.WriteFile(path, contents, 0644)) +} + +func oldSkillContents(t *testing.T) []byte { + t.Helper() + + _, sourceFile, _, _ := runtime.Caller(0) + fixturesDir := filepath.Join(filepath.Dir(sourceFile), "fixtures") + + contents, err := os.ReadFile(filepath.Join(fixturesDir, "0_3_0.md")) + require.NoError(t, err) + return contents +} + +func embeddedSkillContents(t *testing.T) []byte { + t.Helper() + + contents, err := FS.ReadFile(TFCTLSkillPath) + require.NoError(t, err) + return contents +} + +func runMigration(t *testing.T) []MigrationResult { + t.Helper() + + ctx := context.Background() + migration := StartMigration(ctx) + results, err := migration.Wait(ctx) + require.NoError(t, err) + return results +} + +func TestMigrateInstalled_MultipleMigrations(t *testing.T) { + setupMigrationTest(t, "bob", "pi", "codex") + tmpDir := t.TempDir() + oldSkill := oldSkillContents(t) + + t.Chdir(tmpDir) + + bobPath := filepath.Join(".bob", "skills", TFCTLSkillPath) + piPath := filepath.Join(".agents", "skills", TFCTLSkillPath) + codexPath := filepath.Join(".codex", "skills", TFCTLSkillPath) + + writeSkill(t, bobPath, oldSkill) + writeSkill(t, piPath, oldSkill) + writeSkill(t, codexPath, []byte("Not a known skill")) + + results := runMigration(t) + + require.Len(t, results, 2) + absBobPath, err := filepath.Abs(bobPath) + require.NoError(t, err) + absPiPath, err := filepath.Abs(piPath) + require.NoError(t, err) + require.Equal(t, absBobPath, results[0].SkillPath) + require.Equal(t, absPiPath, results[1].SkillPath) + + require.NoError(t, err) + require.Equal(t, "v0.3.0", results[0].PreviousVersion) + require.Equal(t, "v0.3.0", results[1].PreviousVersion) + require.NoError(t, results[0].FailedReason) + require.NoError(t, results[1].FailedReason) + + bobUpgradedContents, err := os.ReadFile(absBobPath) + require.NoError(t, err) + + piUpgradedContents, err := os.ReadFile(absPiPath) + require.NoError(t, err) + + require.Equal(t, embeddedSkillContents(t), bobUpgradedContents) + require.Equal(t, embeddedSkillContents(t), piUpgradedContents) +} + +func TestMigrateInstalled_SkillFileIsSymlink(t *testing.T) { + setupMigrationTest(t, "pi") + tmpDir := t.TempDir() + t.Chdir(tmpDir) + + linkPath := filepath.Join(".agents", "skills", TFCTLSkillPath) + targetPath := filepath.Join(tmpDir, "target", "SKILL.md") + writeSkill(t, targetPath, oldSkillContents(t)) + require.NoError(t, os.MkdirAll(filepath.Dir(linkPath), 0755)) + require.NoError(t, os.Symlink(targetPath, linkPath)) + + results := runMigration(t) + require.Len(t, results, 1) + expectedTarget, err := filepath.EvalSymlinks(targetPath) + require.NoError(t, err) + require.Equal(t, expectedTarget, results[0].SkillPath) + require.Equal(t, "v0.3.0", results[0].PreviousVersion) + require.NoError(t, results[0].FailedReason) + + // Ensure contents were migrated + linkInfo, err := os.Lstat(linkPath) + require.NoError(t, err) + require.True(t, linkInfo.Mode()&os.ModeSymlink != 0) + actual, err := os.ReadFile(linkPath) + require.NoError(t, err) + require.Equal(t, embeddedSkillContents(t), actual) +} + +func TestMigrateInstalled_SkillFileIsBrokenSymlink(t *testing.T) { + setupMigrationTest(t, "pi") + tmpDir := t.TempDir() + t.Chdir(tmpDir) + + linkPath := filepath.Join(".agents", "skills", TFCTLSkillPath) + require.NoError(t, os.MkdirAll(filepath.Dir(linkPath), 0755)) + require.NoError(t, os.Symlink(filepath.Join(tmpDir, "missing", "SKILL.md"), linkPath)) + + results := runMigration(t) + require.Empty(t, results) + _, err := os.Lstat(linkPath) + require.NoError(t, err) +} diff --git a/skills/tfctl/SKILL.md b/skills/tfctl/SKILL.md index ecffa6c..3508b3d 100644 --- a/skills/tfctl/SKILL.md +++ b/skills/tfctl/SKILL.md @@ -38,7 +38,7 @@ tfctl api PATH -X DELETE - **If the session authorizes that resource's class, it succeeds** — that's the human's intent, not a violation; proceed and report the result. - **If it doesn't, `tfctl` refuses with a self-documenting message and prints the exact command to hand back** (including the `harness exec --allow-delete=` a human can use to authorize you). Relay that rather than forcing it; don't run `harness exec` yourself to self-authorize. - **You can't tell in advance whether the session grants a class — so don't guess. Attempt the delete and let the refusal tell you.** The refusal is a plain exit 1 with a message naming the class and the `--allow-delete=` command; that is your cue to relay. This is a grant gap, NOT an auth failure: never report it as an expired token, an `exit code 3`, or tell the human to re-login unless `tfctl` actually says the token is expired/invalid. -- Apply ordinary caution to irreversible deletes (`organizations`, `projects`): they are never covered by the `reversible`/`all` wildcards and must be granted by name. For a high-stakes target, confirm intent with the human first even when the session would allow it. +- Apply ordinary caution to irreversible deletes (`organizations`, `projects`). For a high-stakes resource, confirm intent with the human first even when the session would allow it. ### URL shape: per-workspace subpaths live at `/workspaces/{workspace}/...` diff --git a/skills/tfctl/known_release_hashes b/skills/tfctl/known_release_hashes new file mode 100644 index 0000000..242830d --- /dev/null +++ b/skills/tfctl/known_release_hashes @@ -0,0 +1,5 @@ +# This file is generated by `make prepare-release` and should not be +# edited manually. It lists SHA256 hashes of the SKILL.md embedded within +# each release of tfctl. +4a3a72856d49a4de32b7b1f6a379918a956d3931f8a7ff71c06a1e3e4bd3e34f v0.3.0 +01386dc8dbf4d2cf1b3ea027cd0b2ad3c4dfbbdb3701b75e19937352ddc35b96 v0.4.0-beta