From 38dfe82bfbc61c9950893a0a47498e444dd6cb9f Mon Sep 17 00:00:00 2001 From: Charlie Voiselle <464492+angrycub@users.noreply.github.com> Date: Thu, 23 Apr 2026 17:19:36 -0400 Subject: [PATCH 1/3] add organization port sharing option --- internal/provider/template_resource.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/internal/provider/template_resource.go b/internal/provider/template_resource.go index f053773..5e03152 100644 --- a/internal/provider/template_resource.go +++ b/internal/provider/template_resource.go @@ -40,9 +40,11 @@ import ( ) // Ensure provider defined types fully satisfy framework interfaces. -var _ resource.Resource = &TemplateResource{} -var _ resource.ResourceWithImportState = &TemplateResource{} -var _ resource.ResourceWithConfigValidators = &TemplateResource{} +var ( + _ resource.Resource = &TemplateResource{} + _ resource.ResourceWithImportState = &TemplateResource{} + _ resource.ResourceWithConfigValidators = &TemplateResource{} +) func NewTemplateResource() resource.Resource { return &TemplateResource{} @@ -390,7 +392,7 @@ func (r *TemplateResource) Schema(ctx context.Context, req resource.SchemaReques Optional: true, Computed: true, Validators: []validator.String{ - stringvalidator.OneOfCaseInsensitive(string(codersdk.WorkspaceAgentPortShareLevelAuthenticated), string(codersdk.WorkspaceAgentPortShareLevelOwner), string(codersdk.WorkspaceAgentPortShareLevelPublic)), + stringvalidator.OneOfCaseInsensitive(string(codersdk.WorkspaceAgentPortShareLevelAuthenticated), string(codersdk.WorkspaceAgentPortShareLevelOrganization), string(codersdk.WorkspaceAgentPortShareLevelOwner), string(codersdk.WorkspaceAgentPortShareLevelPublic)), }, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), @@ -1251,11 +1253,11 @@ func markActive(ctx context.Context, client *codersdk.Client, templateID uuid.UU } func convertACLToRequest(curACL codersdk.TemplateACL, newACL ACL) codersdk.UpdateTemplateACL { - var userPerms = make(map[string]codersdk.TemplateRole) + userPerms := make(map[string]codersdk.TemplateRole) for _, perm := range newACL.UserPermissions { userPerms[perm.ID.ValueString()] = codersdk.TemplateRole(perm.Role.ValueString()) } - var groupPerms = make(map[string]codersdk.TemplateRole) + groupPerms := make(map[string]codersdk.TemplateRole) for _, perm := range newACL.GroupPermissions { groupPerms[perm.ID.ValueString()] = codersdk.TemplateRole(perm.Role.ValueString()) } @@ -1598,7 +1600,6 @@ func tfVariablesChanged(prevs []PreviousTemplateVersion, planned *TemplateVersio } } return true - } func formatLogs(err error, logs []codersdk.ProvisionerJobLog) string { From 7e0b533bf719941fd5bf36e5b0f77202655ae385 Mon Sep 17 00:00:00 2001 From: Charlie Voiselle <464492+angrycub@users.noreply.github.com> Date: Tue, 19 May 2026 09:58:58 -0500 Subject: [PATCH 2/3] test: add max_port_share_level tests for all valid constants and invalid input Adds MaxPortShareLevelConstants (enterprise) stepping through owner, authenticated, organization, and public in sequence, and InvalidMaxPortShareLevel (non-enterprise) verifying that an unrecognized value is rejected at plan time by the schema validator. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- internal/provider/template_resource_test.go | 65 ++++++++++++++++++--- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/internal/provider/template_resource_test.go b/internal/provider/template_resource_test.go index 971de6e..844780c 100644 --- a/internal/provider/template_resource_test.go +++ b/internal/provider/template_resource_test.go @@ -636,6 +636,34 @@ func TestAccTemplateResource(t *testing.T) { }, }) }) + + t.Run("InvalidMaxPortShareLevel", func(t *testing.T) { + cfg1 := testAccTemplateResourceConfig{ + URL: client.URL.String(), + Token: client.SessionToken(), + Name: ptr.Ref("example-template"), + Versions: []testAccTemplateVersionConfig{ + { + Directory: &exTemplateOne, + Active: ptr.Ref(true), + }, + }, + ACL: testAccTemplateACLConfig{null: true}, + MaxPortShareLevel: ptr.Ref("invalid"), + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IsUnitTest: true, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: cfg1.String(t), + ExpectError: regexp.MustCompile(`value must be one of`), + }, + }, + }) + }) } func TestAccTemplateResourceEnterprise(t *testing.T) { @@ -790,10 +818,10 @@ func TestAccTemplateResourceEnterprise(t *testing.T) { }) }) - // Verifies that when `max_port_share_level` is set to to the default value, - // an update request that would return HTTP Not Modified is not sent. - t.Run("DefaultMaxPortShareLevel", func(t *testing.T) { - cfg1 := testAccTemplateResourceConfig{ + // Verifies that all valid max_port_share_level constants are accepted and + // round-trip correctly through the API, including updates between values. + t.Run("MaxPortShareLevelConstants", func(t *testing.T) { + baseCfg := testAccTemplateResourceConfig{ URL: client.URL.String(), Token: client.SessionToken(), Name: ptr.Ref("example-template"), @@ -803,18 +831,41 @@ func TestAccTemplateResourceEnterprise(t *testing.T) { Active: ptr.Ref(true), }, }, - MaxPortShareLevel: ptr.Ref("owner"), } + cfgOwner := baseCfg + cfgOwner.MaxPortShareLevel = ptr.Ref("owner") + + cfgAuthenticated := baseCfg + cfgAuthenticated.MaxPortShareLevel = ptr.Ref("authenticated") + + cfgOrganization := baseCfg + cfgOrganization.MaxPortShareLevel = ptr.Ref("organization") + + cfgPublic := baseCfg + cfgPublic.MaxPortShareLevel = ptr.Ref("public") + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, IsUnitTest: true, ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, Steps: []resource.TestStep{ { - Config: cfg1.String(t), + Config: cfgOwner.String(t), Check: resource.TestCheckResourceAttr("coderd_template.test", "max_port_share_level", "owner"), }, + { + Config: cfgAuthenticated.String(t), + Check: resource.TestCheckResourceAttr("coderd_template.test", "max_port_share_level", "authenticated"), + }, + { + Config: cfgOrganization.String(t), + Check: resource.TestCheckResourceAttr("coderd_template.test", "max_port_share_level", "organization"), + }, + { + Config: cfgPublic.String(t), + Check: resource.TestCheckResourceAttr("coderd_template.test", "max_port_share_level", "public"), + }, }, }) }) @@ -1595,7 +1646,6 @@ func TestReconcileVersionIDs(t *testing.T) { } for _, c := range cases { - c := c t.Run(c.Name, func(t *testing.T) { t.Parallel() @@ -1606,6 +1656,5 @@ func TestReconcileVersionIDs(t *testing.T) { require.Equal(t, c.expectedVersions, c.planVersions) } }) - } } From 73452a1d73ccf8bea82ba6484e11d450f277dc38 Mon Sep 17 00:00:00 2001 From: Charlie Voiselle <464492+angrycub@users.noreply.github.com> Date: Tue, 19 May 2026 12:06:11 -0500 Subject: [PATCH 3/3] test: add integration test for max_port_share_level=organization Adds a Docker-based integration test that applies a template with max_port_share_level set to "organization" against a licensed Coder deployment and asserts the value round-trips correctly via codersdk. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- integration/integration_test.go | 11 +++++++++++ .../example-template/main.tf | 1 + integration/template-port-share-test/main.tf | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 integration/template-port-share-test/example-template/main.tf create mode 100644 integration/template-port-share-test/main.tf diff --git a/integration/integration_test.go b/integration/integration_test.go index d91112a..26cf683 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -145,6 +145,17 @@ func TestIntegration(t *testing.T) { assert.Contains(t, groupSync.Mapping["mixed_group"], adminGroup.ID) }, }, + { + name: "template-port-share-test", + preF: func(t testing.TB, c *codersdk.Client) {}, + assertF: func(t testing.TB, c *codersdk.Client) { + templates, err := c.Templates(ctx, codersdk.TemplateFilter{}) + require.NoError(t, err) + require.Len(t, templates, 1) + require.Equal(t, "port-share-test", templates[0].Name) + require.Equal(t, codersdk.WorkspaceAgentPortShareLevelOrganization, templates[0].MaxPortShareLevel) + }, + }, { name: "template-test", preF: func(t testing.TB, c *codersdk.Client) {}, diff --git a/integration/template-port-share-test/example-template/main.tf b/integration/template-port-share-test/example-template/main.tf new file mode 100644 index 0000000..3972222 --- /dev/null +++ b/integration/template-port-share-test/example-template/main.tf @@ -0,0 +1 @@ +resource "null_resource" "a" {} diff --git a/integration/template-port-share-test/main.tf b/integration/template-port-share-test/main.tf new file mode 100644 index 0000000..d70960e --- /dev/null +++ b/integration/template-port-share-test/main.tf @@ -0,0 +1,19 @@ +terraform { + required_providers { + coderd = { + source = "coder/coderd" + version = ">=0.0.0" + } + } +} + +resource "coderd_template" "port_share" { + name = "port-share-test" + max_port_share_level = "organization" + versions = [ + { + directory = "./example-template" + active = true + } + ] +}