Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
213 changes: 213 additions & 0 deletions examples/policy_set_parameter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
from __future__ import annotations

import argparse
import os

from pytfe import TFEClient, TFEConfig
from pytfe.models import (
PolicySetParameterCreateOptions,
PolicySetParameterListOptions,
PolicySetParameterUpdateOptions,
)


def _print_header(title: str):
print("\n" + "=" * 80)
print(title)
print("=" * 80)


def main():
parser = argparse.ArgumentParser(
description="Policy Set Parameters demo for python-tfe SDK"
)
parser.add_argument(
"--address", default=os.getenv("TFE_ADDRESS", "https://app.terraform.io")
)
parser.add_argument("--token", default=os.getenv("TFE_TOKEN", ""))
parser.add_argument("--policy-set-id", required=True, help="Policy Set ID")
parser.add_argument(
"--page-size",
type=int,
default=100,
help="Page size for fetching parameters",
)
parser.add_argument("--create", action="store_true", help="Create a test parameter")
parser.add_argument("--read", action="store_true", help="Read a specific parameter")
parser.add_argument("--update", action="store_true", help="Update a parameter")
parser.add_argument("--delete", action="store_true", help="Delete a parameter")
parser.add_argument(
"--parameter-id", help="Parameter ID for read/update/delete operation"
)
parser.add_argument("--key", help="Parameter key for creation/update")
parser.add_argument("--value", help="Parameter value for creation/update")
parser.add_argument(
"--sensitive", action="store_true", help="Mark parameter as sensitive"
)
args = parser.parse_args()

cfg = TFEConfig(address=args.address, token=args.token)
client = TFEClient(cfg)

# 1) List all parameters for the policy set
_print_header(f"Listing parameters for policy set: {args.policy_set_id}")

options = PolicySetParameterListOptions(
page_size=args.page_size,
)

param_count = 0
for param in client.policy_set_parameters.list(args.policy_set_id, options):
param_count += 1
# Sensitive parameters will have masked values
value_display = "***SENSITIVE***" if param.sensitive else param.value
print(f"- {param.id}")
print(f" Key: {param.key}")
print(f" Value: {value_display}")
print(f" Category: {param.category.value}")
print(f" Sensitive: {param.sensitive}")
print()

if param_count == 0:
print("No parameters found.")
else:
print(f"Total: {param_count} parameters")

# 2) Read a specific parameter (if --read flag is provided)
if args.read:
if not args.parameter_id:
print("Error: --parameter-id is required for read operation")
return

_print_header(f"Reading parameter: {args.parameter_id}")

param = client.policy_set_parameters.read(args.policy_set_id, args.parameter_id)

print(f"Parameter ID: {param.id}")
print(f" Key: {param.key}")
value_display = "***SENSITIVE***" if param.sensitive else param.value
print(f" Value: {value_display}")
print(f" Category: {param.category.value}")
print(f" Sensitive: {param.sensitive}")

# 3) Update a parameter (if --update flag is provided)
if args.update:
if not args.parameter_id:
print("Error: --parameter-id is required for update operation")
return

_print_header(f"Updating parameter: {args.parameter_id}")

# First read the current parameter to show before state
current_param = client.policy_set_parameters.read(
args.policy_set_id, args.parameter_id
)
print("Before update:")
print(f" Key: {current_param.key}")
value_display = (
"***SENSITIVE***" if current_param.sensitive else current_param.value
)
print(f" Value: {value_display}")
print(f" Sensitive: {current_param.sensitive}")

# Update the parameter
update_options = PolicySetParameterUpdateOptions(
key=args.key if args.key else None,
value=args.value if args.value else None,
sensitive=args.sensitive if args.sensitive else None,
)

updated_param = client.policy_set_parameters.update(
args.policy_set_id, args.parameter_id, update_options
)

print("\nAfter update:")
print(f" Key: {updated_param.key}")
value_display = (
"***SENSITIVE***" if updated_param.sensitive else updated_param.value
)
print(f" Value: {value_display}")
print(f" Sensitive: {updated_param.sensitive}")

# 4) Delete a parameter (if --delete flag is provided)
if args.delete:
if not args.parameter_id:
print("Error: --parameter-id is required for delete operation")
return

_print_header(f"Deleting parameter: {args.parameter_id}")

# First read the parameter to show what's being deleted
try:
param_to_delete = client.policy_set_parameters.read(
args.policy_set_id, args.parameter_id
)
print("Parameter to delete:")
print(f" ID: {param_to_delete.id}")
print(f" Key: {param_to_delete.key}")
value_display = (
"***SENSITIVE***"
if param_to_delete.sensitive
else param_to_delete.value
)
print(f" Value: {value_display}")
print(f" Sensitive: {param_to_delete.sensitive}")
except Exception as e:
print(f"Error reading parameter: {e}")
return

# Delete the parameter
client.policy_set_parameters.delete(args.policy_set_id, args.parameter_id)
print(f"\n Successfully deleted parameter: {args.parameter_id}")

# List remaining parameters
_print_header("Listing parameters after deletion")
print("Remaining parameters:")
remaining_count = 0
for param in client.policy_set_parameters.list(args.policy_set_id):
remaining_count += 1
value_display = "***SENSITIVE***" if param.sensitive else param.value
print(f"- {param.key}: {value_display} (sensitive={param.sensitive})")

if remaining_count == 0:
print("No parameters remaining.")
else:
print(f"\nTotal: {remaining_count} parameters")

# 5) Create a new parameter (if --create flag is provided)
if args.create:
if not args.key:
print("Error: --key is required for create operation")
return

_print_header(f"Creating new parameter with key: {args.key}")

create_options = PolicySetParameterCreateOptions(
key=args.key,
value=args.value if args.value else "",
sensitive=args.sensitive,
)

new_param = client.policy_set_parameters.create(
args.policy_set_id, create_options
)

print(f"Created parameter: {new_param.id}")
print(f" Key: {new_param.key}")
value_display = "***SENSITIVE***" if new_param.sensitive else new_param.value
print(f" Value: {value_display}")
print(f" Category: {new_param.category.value}")
print(f" Sensitive: {new_param.sensitive}")

# List again to show the new parameter
_print_header("Listing parameters after creation")
param_count = 0
for param in client.policy_set_parameters.list(args.policy_set_id):
param_count += 1
value_display = "***SENSITIVE***" if param.sensitive else param.value
print(f"- {param.key}: {value_display} (sensitive={param.sensitive})")
print(f"\nTotal: {param_count} parameters")


if __name__ == "__main__":
main()
2 changes: 2 additions & 0 deletions src/pytfe/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from .resources.policy_evaluation import PolicyEvaluations
from .resources.policy_set import PolicySets
from .resources.policy_set_outcome import PolicySets as PolicySetOutcomes
from .resources.policy_set_parameter import PolicySetParameters
from .resources.policy_set_version import PolicySetVersions
from .resources.projects import Projects
from .resources.query_run import QueryRuns
Expand Down Expand Up @@ -84,6 +85,7 @@ def __init__(self, config: TFEConfig | None = None):
self.policy_evaluations = PolicyEvaluations(self._transport)
self.policy_checks = PolicyChecks(self._transport)
self.policy_sets = PolicySets(self._transport)
self.policy_set_parameters = PolicySetParameters(self._transport)
self.policy_set_outcomes = PolicySetOutcomes(self._transport)
self.policy_set_versions = PolicySetVersions(self._transport)

Expand Down
29 changes: 29 additions & 0 deletions src/pytfe/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,3 +460,32 @@ class InvalidPolicyEvaluationIDError(InvalidValues):

def __init__(self, message: str = "invalid value for policy evaluation ID"):
super().__init__(message)


# Policy Set Parameter errors
class InvalidParamIDError(InvalidValues):
"""Raised when an invalid policy set parameter ID is provided."""

def __init__(self, message: str = "invalid value for parameter ID"):
super().__init__(message)


class RequiredCategoryError(RequiredFieldMissing):
"""Raised when a required category field is missing."""

def __init__(self, message: str = "category is required"):
super().__init__(message)


class InvalidCategoryError(InvalidValues):
"""Raised when an invalid category field is provided."""

def __init__(self, message: str = "category must be policy-set"):
super().__init__(message)


class RequiredKeyError(RequiredFieldMissing):
"""Raised when a required key field is missing."""

def __init__(self, message: str = "key is required"):
super().__init__(message)
11 changes: 11 additions & 0 deletions src/pytfe/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@
PolicySetRemoveWorkspacesOptions,
PolicySetUpdateOptions,
)
from .policy_set_parameter import (
PolicySetParameter,
PolicySetParameterCreateOptions,
PolicySetParameterListOptions,
PolicySetParameterUpdateOptions,
)
from .policy_types import (
EnforcementLevel,
PolicyKind,
Expand Down Expand Up @@ -586,6 +592,11 @@
"PolicySetRemoveWorkspaceExclusionsOptions",
"PolicySetRemoveProjectsOptions",
"PolicySetUpdateOptions",
# Policy Set Parameters
"PolicySetParameter",
"PolicySetParameterCreateOptions",
"PolicySetParameterListOptions",
"PolicySetParameterUpdateOptions",
"PolicyKind",
"EnforcementLevel",
# Variable Sets
Expand Down
44 changes: 44 additions & 0 deletions src/pytfe/models/policy_set_parameter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from __future__ import annotations

from pydantic import BaseModel, ConfigDict, Field

from .policy_set import PolicySet
from .variable import CategoryType


class PolicySetParameter(BaseModel):
model_config = ConfigDict(populate_by_name=True, validate_by_name=True)

id: str
key: str = Field(..., alias="key")
value: str | None = Field(None, alias="value")
category: CategoryType = Field(..., alias="category")
sensitive: bool = Field(..., alias="sensitive")

# relations
policy_set: PolicySet = Field(..., alias="configurable")


class PolicySetParameterListOptions(BaseModel):
model_config = ConfigDict(populate_by_name=True, validate_by_name=True)

page_size: int | None = Field(None, alias="page[size]")


class PolicySetParameterCreateOptions(BaseModel):
model_config = ConfigDict(populate_by_name=True, validate_by_name=True)

key: str = Field(..., alias="key")
value: str | None = Field(None, alias="value")

# Required: The Category of the parameter, should always be "policy-set"
category: CategoryType = Field(default=CategoryType.POLICY_SET, alias="category")
sensitive: bool | None = Field(None, alias="sensitive")


class PolicySetParameterUpdateOptions(BaseModel):
model_config = ConfigDict(populate_by_name=True, validate_by_name=True)

key: str | None = Field(None, alias="key")
value: str | None = Field(None, alias="value")
sensitive: bool | None = Field(None, alias="sensitive")
Loading
Loading