Skip to content
Open
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
19 changes: 19 additions & 0 deletions lib/tfgen/testdata/TestGenerate_AccessListMemberWithScope.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
resource "teleport_access_list_member" "some-member" {
scope = "/some/member-scope"
header = {
kind = "access_list_member"
version = "v1"
metadata = {
name = "some-member"
}
}

spec = {
access_list = "some-id"
name = "some-member"
reason = "some reason"
added_by = "admin"
ineligible_status = "0"
membership_kind = "1"
}
}
31 changes: 31 additions & 0 deletions lib/tfgen/testdata/TestGenerate_AccessListWithScope.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
resource "teleport_access_list" "some-access-list" {
scope = "/some/scope"
header = {
kind = "access_list"
version = "v1"
metadata = {
name = "some-access-list"
}
}

spec = {
description = "An example scoped access list"
owners = [{
description = "some description"
ineligible_status = "0"
membership_kind = "1"
name = "llama"
}]
audit = {
next_audit_date = "2023-02-02T00:00:00Z"
recurrence = {
frequency = "3"
day_of_month = "1"
}
notifications = {
start = "336h0m0s"
}
}
title = "My Access List"
}
}
8 changes: 8 additions & 0 deletions lib/tfgen/tfgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,14 @@ func generateResource(
// a header field, while other resources expect these fields as top-level fields.
_, hasHeaderField := resource.(*headerResourceWrapper)
if hasHeaderField {
// Access list resources have top level scope field:
scope := msg.AttributeNamed("scope")
if scope != nil && !opts.fieldsToOmit["scope"] {
tokens := valueToTokens(fieldPath{"scope"}, scope.Value, opts, false /* emitZeroVal */)
if tokens != nil {
resourceBlock.Body().SetAttributeRaw("scope", tokens)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Qualify scoped access-list-member parents

When tfgen is given a scoped access_list_member whose Spec.AccessList is a bare list name (the new test constructs this exact case), this line emits scope, but the generated HCL still leaves spec.access_list bare. The access-list service treats any non-empty member scope as requiring spec.access_list to be scope-qualified (ParentListOf in lib/accesslists/scopequalifiedname.go:142-149 calls ParseScopeQualifiedName), so Terraform apply fails before creating the member; either qualify the parent (/scope::name) when emitting scoped members or reject/normalize this input.

Useful? React with 👍 / 👎.

}
}
if header := msg.AttributeNamed("header"); header != nil && !opts.fieldsToOmit["header"] {
tokens := messageToTokens(fieldPath{"header"}, header.Value, opts)
if tokens != nil {
Expand Down
46 changes: 46 additions & 0 deletions lib/tfgen/tfgen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,3 +499,49 @@ func goldenTest(t *testing.T, resource tfgen.Resource, opts ...tfgen.GenerateOpt
),
)
}

func TestGenerate_AccessListWithScope(t *testing.T) {
t.Parallel()

al, err := accesslist.NewAccessListWithScope(
header.Metadata{Name: "some-access-list"},
accesslist.Spec{
Title: "My Access List",
Description: "An example scoped access list",
Owners: []accesslist.Owner{
{Name: "llama", Description: "some description"},
},
Audit: accesslist.Audit{
NextAuditDate: time.Date(2023, 02, 02, 0, 0, 0, 0, time.UTC),
Recurrence: accesslist.Recurrence{
Frequency: accesslist.ThreeMonths,
DayOfMonth: accesslist.FirstDayOfMonth,
},
},
},
"/some/scope",
)
require.NoError(t, err)

alProto := tfgen.WrapHeaderResource(accesslistconv.ToProto(al))
goldenTest(t, alProto)
}

func TestGenerate_AccessListMemberWithScope(t *testing.T) {
t.Parallel()

member, err := accesslist.NewAccessListMemberWithScope(
header.Metadata{Name: "some-member"},
accesslist.AccessListMemberSpec{
AccessList: "some-id",
Name: "some-member",
Reason: "some reason",
AddedBy: "admin",
},
"/some/member-scope",
)
require.NoError(t, err)

memProto := tfgen.WrapHeaderResource(accesslistconv.ToMemberProto(member))
goldenTest(t, memProto)
}
Loading