Add in audit review recurrence presets. (#32843)

Access Lists now have audit review recurrence presets. These allow users to
specify review frequencies of 1, 3, 6, or 12 months, and specify the 1st,
15th, or last days of the target month. Presets have been used for their
simplicity over other various recurrence definition mechanisms, as these
presets are much clearer than many of the other options.
This commit is contained in:
Michael Wilson
2023-10-03 22:36:05 +00:00
committed by GitHub
parent 64832452c1
commit 049363b882
18 changed files with 917 additions and 315 deletions
+6 -5
View File
@@ -16,8 +16,8 @@ package client
import (
"testing"
"time"
"github.com/jonboulle/clockwork"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
@@ -32,6 +32,7 @@ import (
// primarily to catch potential issues with using our "mixed" gogo + regular protobuf
// strategy.
func TestEventEqual(t *testing.T) {
clock := clockwork.NewFakeClock()
app1, err := types.NewAppV3(types.Metadata{
Name: "app1",
}, types.AppSpecV3{
@@ -56,8 +57,8 @@ func TestEventEqual(t *testing.T) {
})
require.NoError(t, err)
accessList1 := newAccessList(t, "1")
accessList2 := newAccessList(t, "2")
accessList1 := newAccessList(t, "1", clock)
accessList2 := newAccessList(t, "2", clock)
tests := []struct {
name string
@@ -158,7 +159,7 @@ func TestEventEqual(t *testing.T) {
}
}
func newAccessList(t *testing.T, name string) *accesslist.AccessList {
func newAccessList(t *testing.T, name string, clock clockwork.Clock) *accesslist.AccessList {
t.Helper()
accessList, err := accesslist.NewAccessList(
@@ -179,7 +180,7 @@ func newAccessList(t *testing.T, name string) *accesslist.AccessList {
},
},
Audit: accesslist.Audit{
Frequency: time.Hour,
NextAuditDate: clock.Now(),
},
MembershipRequires: accesslist.Requires{
Roles: []string{"mrole1", "mrole2"},
@@ -25,7 +25,6 @@ import (
v11 "github.com/gravitational/teleport/api/gen/proto/go/teleport/trait/v1"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
durationpb "google.golang.org/protobuf/types/known/durationpb"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
@@ -38,6 +37,115 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// ReviewFrequency is the frequency of reviews.
type ReviewFrequency int32
const (
ReviewFrequency_REVIEW_FREQUENCY_UNSPECIFIED ReviewFrequency = 0
ReviewFrequency_REVIEW_FREQUENCY_ONE_MONTH ReviewFrequency = 1
ReviewFrequency_REVIEW_FREQUENCY_THREE_MONTHS ReviewFrequency = 3
ReviewFrequency_REVIEW_FREQUENCY_SIX_MONTHS ReviewFrequency = 6
ReviewFrequency_REVIEW_FREQUENCY_ONE_YEAR ReviewFrequency = 12
)
// Enum value maps for ReviewFrequency.
var (
ReviewFrequency_name = map[int32]string{
0: "REVIEW_FREQUENCY_UNSPECIFIED",
1: "REVIEW_FREQUENCY_ONE_MONTH",
3: "REVIEW_FREQUENCY_THREE_MONTHS",
6: "REVIEW_FREQUENCY_SIX_MONTHS",
12: "REVIEW_FREQUENCY_ONE_YEAR",
}
ReviewFrequency_value = map[string]int32{
"REVIEW_FREQUENCY_UNSPECIFIED": 0,
"REVIEW_FREQUENCY_ONE_MONTH": 1,
"REVIEW_FREQUENCY_THREE_MONTHS": 3,
"REVIEW_FREQUENCY_SIX_MONTHS": 6,
"REVIEW_FREQUENCY_ONE_YEAR": 12,
}
)
func (x ReviewFrequency) Enum() *ReviewFrequency {
p := new(ReviewFrequency)
*p = x
return p
}
func (x ReviewFrequency) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ReviewFrequency) Descriptor() protoreflect.EnumDescriptor {
return file_teleport_accesslist_v1_accesslist_proto_enumTypes[0].Descriptor()
}
func (ReviewFrequency) Type() protoreflect.EnumType {
return &file_teleport_accesslist_v1_accesslist_proto_enumTypes[0]
}
func (x ReviewFrequency) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ReviewFrequency.Descriptor instead.
func (ReviewFrequency) EnumDescriptor() ([]byte, []int) {
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{0}
}
// ReviewDayOfMonth is the day of month that reviews will repeat on.
type ReviewDayOfMonth int32
const (
ReviewDayOfMonth_REVIEW_DAY_OF_MONTH_UNSPECIFIED ReviewDayOfMonth = 0
ReviewDayOfMonth_REVIEW_DAY_OF_MONTH_FIRST ReviewDayOfMonth = 1
ReviewDayOfMonth_REVIEW_DAY_OF_MONTH_FIFTEENTH ReviewDayOfMonth = 15
ReviewDayOfMonth_REVIEW_DAY_OF_MONTH_LAST ReviewDayOfMonth = 31
)
// Enum value maps for ReviewDayOfMonth.
var (
ReviewDayOfMonth_name = map[int32]string{
0: "REVIEW_DAY_OF_MONTH_UNSPECIFIED",
1: "REVIEW_DAY_OF_MONTH_FIRST",
15: "REVIEW_DAY_OF_MONTH_FIFTEENTH",
31: "REVIEW_DAY_OF_MONTH_LAST",
}
ReviewDayOfMonth_value = map[string]int32{
"REVIEW_DAY_OF_MONTH_UNSPECIFIED": 0,
"REVIEW_DAY_OF_MONTH_FIRST": 1,
"REVIEW_DAY_OF_MONTH_FIFTEENTH": 15,
"REVIEW_DAY_OF_MONTH_LAST": 31,
}
)
func (x ReviewDayOfMonth) Enum() *ReviewDayOfMonth {
p := new(ReviewDayOfMonth)
*p = x
return p
}
func (x ReviewDayOfMonth) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (ReviewDayOfMonth) Descriptor() protoreflect.EnumDescriptor {
return file_teleport_accesslist_v1_accesslist_proto_enumTypes[1].Descriptor()
}
func (ReviewDayOfMonth) Type() protoreflect.EnumType {
return &file_teleport_accesslist_v1_accesslist_proto_enumTypes[1]
}
func (x ReviewDayOfMonth) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use ReviewDayOfMonth.Descriptor instead.
func (ReviewDayOfMonth) EnumDescriptor() ([]byte, []int) {
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{1}
}
// IneligibleStatus describes how the user is ineligible.
type IneligibleStatus int32
@@ -86,11 +194,11 @@ func (x IneligibleStatus) String() string {
}
func (IneligibleStatus) Descriptor() protoreflect.EnumDescriptor {
return file_teleport_accesslist_v1_accesslist_proto_enumTypes[0].Descriptor()
return file_teleport_accesslist_v1_accesslist_proto_enumTypes[2].Descriptor()
}
func (IneligibleStatus) Type() protoreflect.EnumType {
return &file_teleport_accesslist_v1_accesslist_proto_enumTypes[0]
return &file_teleport_accesslist_v1_accesslist_proto_enumTypes[2]
}
func (x IneligibleStatus) Number() protoreflect.EnumNumber {
@@ -99,7 +207,7 @@ func (x IneligibleStatus) Number() protoreflect.EnumNumber {
// Deprecated: Use IneligibleStatus.Descriptor instead.
func (IneligibleStatus) EnumDescriptor() ([]byte, []int) {
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{0}
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{2}
}
// AccessList describes the basic building block of access grants, which are
@@ -343,10 +451,10 @@ type AccessListAudit struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// frequency is a duration that describes how often an access list must be audited.
Frequency *durationpb.Duration `protobuf:"bytes,1,opt,name=frequency,proto3" json:"frequency,omitempty"`
// next_audit_date is when the next audit date should be done by.
NextAuditDate *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=next_audit_date,json=nextAuditDate,proto3" json:"next_audit_date,omitempty"`
// recurrence is the recurrence definition
Recurrence *Recurrence `protobuf:"bytes,3,opt,name=recurrence,proto3" json:"recurrence,omitempty"`
}
func (x *AccessListAudit) Reset() {
@@ -381,13 +489,6 @@ func (*AccessListAudit) Descriptor() ([]byte, []int) {
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{3}
}
func (x *AccessListAudit) GetFrequency() *durationpb.Duration {
if x != nil {
return x.Frequency
}
return nil
}
func (x *AccessListAudit) GetNextAuditDate() *timestamppb.Timestamp {
if x != nil {
return x.NextAuditDate
@@ -395,6 +496,71 @@ func (x *AccessListAudit) GetNextAuditDate() *timestamppb.Timestamp {
return nil
}
func (x *AccessListAudit) GetRecurrence() *Recurrence {
if x != nil {
return x.Recurrence
}
return nil
}
// Recurrence is the definition for when reviews will be scheduled.
type Recurrence struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// frequency is the frequency of reviews.
Frequency ReviewFrequency `protobuf:"varint,1,opt,name=frequency,proto3,enum=teleport.accesslist.v1.ReviewFrequency" json:"frequency,omitempty"`
// day_of_month is the day of month that reviews will be scheduled on.
DayOfMonth ReviewDayOfMonth `protobuf:"varint,2,opt,name=day_of_month,json=dayOfMonth,proto3,enum=teleport.accesslist.v1.ReviewDayOfMonth" json:"day_of_month,omitempty"`
}
func (x *Recurrence) Reset() {
*x = Recurrence{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Recurrence) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Recurrence) ProtoMessage() {}
func (x *Recurrence) ProtoReflect() protoreflect.Message {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Recurrence.ProtoReflect.Descriptor instead.
func (*Recurrence) Descriptor() ([]byte, []int) {
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{4}
}
func (x *Recurrence) GetFrequency() ReviewFrequency {
if x != nil {
return x.Frequency
}
return ReviewFrequency_REVIEW_FREQUENCY_UNSPECIFIED
}
func (x *Recurrence) GetDayOfMonth() ReviewDayOfMonth {
if x != nil {
return x.DayOfMonth
}
return ReviewDayOfMonth_REVIEW_DAY_OF_MONTH_UNSPECIFIED
}
// AccessListRequires describes a requirement section for an access list. A user must
// meet the following criteria to obtain the specific access to the list.
type AccessListRequires struct {
@@ -411,7 +577,7 @@ type AccessListRequires struct {
func (x *AccessListRequires) Reset() {
*x = AccessListRequires{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[4]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -424,7 +590,7 @@ func (x *AccessListRequires) String() string {
func (*AccessListRequires) ProtoMessage() {}
func (x *AccessListRequires) ProtoReflect() protoreflect.Message {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[4]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -437,7 +603,7 @@ func (x *AccessListRequires) ProtoReflect() protoreflect.Message {
// Deprecated: Use AccessListRequires.ProtoReflect.Descriptor instead.
func (*AccessListRequires) Descriptor() ([]byte, []int) {
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{4}
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{5}
}
func (x *AccessListRequires) GetRoles() []string {
@@ -469,7 +635,7 @@ type AccessListGrants struct {
func (x *AccessListGrants) Reset() {
*x = AccessListGrants{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[5]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -482,7 +648,7 @@ func (x *AccessListGrants) String() string {
func (*AccessListGrants) ProtoMessage() {}
func (x *AccessListGrants) ProtoReflect() protoreflect.Message {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[5]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -495,7 +661,7 @@ func (x *AccessListGrants) ProtoReflect() protoreflect.Message {
// Deprecated: Use AccessListGrants.ProtoReflect.Descriptor instead.
func (*AccessListGrants) Descriptor() ([]byte, []int) {
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{5}
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{6}
}
func (x *AccessListGrants) GetRoles() []string {
@@ -527,7 +693,7 @@ type Member struct {
func (x *Member) Reset() {
*x = Member{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[6]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -540,7 +706,7 @@ func (x *Member) String() string {
func (*Member) ProtoMessage() {}
func (x *Member) ProtoReflect() protoreflect.Message {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[6]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -553,7 +719,7 @@ func (x *Member) ProtoReflect() protoreflect.Message {
// Deprecated: Use Member.ProtoReflect.Descriptor instead.
func (*Member) Descriptor() ([]byte, []int) {
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{6}
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{7}
}
func (x *Member) GetHeader() *v1.ResourceHeader {
@@ -596,7 +762,7 @@ type MemberSpec struct {
func (x *MemberSpec) Reset() {
*x = MemberSpec{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[7]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -609,7 +775,7 @@ func (x *MemberSpec) String() string {
func (*MemberSpec) ProtoMessage() {}
func (x *MemberSpec) ProtoReflect() protoreflect.Message {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[7]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -622,7 +788,7 @@ func (x *MemberSpec) ProtoReflect() protoreflect.Message {
// Deprecated: Use MemberSpec.ProtoReflect.Descriptor instead.
func (*MemberSpec) Descriptor() ([]byte, []int) {
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{7}
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{8}
}
func (x *MemberSpec) GetAccessList() string {
@@ -689,7 +855,7 @@ type Review struct {
func (x *Review) Reset() {
*x = Review{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[8]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -702,7 +868,7 @@ func (x *Review) String() string {
func (*Review) ProtoMessage() {}
func (x *Review) ProtoReflect() protoreflect.Message {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[8]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -715,7 +881,7 @@ func (x *Review) ProtoReflect() protoreflect.Message {
// Deprecated: Use Review.ProtoReflect.Descriptor instead.
func (*Review) Descriptor() ([]byte, []int) {
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{8}
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{9}
}
func (x *Review) GetHeader() *v1.ResourceHeader {
@@ -754,7 +920,7 @@ type ReviewSpec struct {
func (x *ReviewSpec) Reset() {
*x = ReviewSpec{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[9]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -767,7 +933,7 @@ func (x *ReviewSpec) String() string {
func (*ReviewSpec) ProtoMessage() {}
func (x *ReviewSpec) ProtoReflect() protoreflect.Message {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[9]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -780,7 +946,7 @@ func (x *ReviewSpec) ProtoReflect() protoreflect.Message {
// Deprecated: Use ReviewSpec.ProtoReflect.Descriptor instead.
func (*ReviewSpec) Descriptor() ([]byte, []int) {
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{9}
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{10}
}
func (x *ReviewSpec) GetAccessList() string {
@@ -824,18 +990,20 @@ type ReviewChanges struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// audit_frequency_changed is populated if the audit frequency was changed.
FrequencyChanged *durationpb.Duration `protobuf:"bytes,1,opt,name=frequency_changed,json=frequencyChanged,proto3" json:"frequency_changed,omitempty"`
// membership_requirements_changed is populated if the requirements were changed as part of this review.
MembershipRequirementsChanged *AccessListRequires `protobuf:"bytes,2,opt,name=membership_requirements_changed,json=membershipRequirementsChanged,proto3" json:"membership_requirements_changed,omitempty"`
// removed_members contains the members that were removed as part of this review.
RemovedMembers []string `protobuf:"bytes,3,rep,name=removed_members,json=removedMembers,proto3" json:"removed_members,omitempty"`
// review_frequency_changed is populated if the review frequency has changed.
ReviewFrequencyChanged ReviewFrequency `protobuf:"varint,4,opt,name=review_frequency_changed,json=reviewFrequencyChanged,proto3,enum=teleport.accesslist.v1.ReviewFrequency" json:"review_frequency_changed,omitempty"`
// review_day_of_month changed is populated if the review day of month has changed.
ReviewDayOfMonthChanged ReviewDayOfMonth `protobuf:"varint,5,opt,name=review_day_of_month_changed,json=reviewDayOfMonthChanged,proto3,enum=teleport.accesslist.v1.ReviewDayOfMonth" json:"review_day_of_month_changed,omitempty"`
}
func (x *ReviewChanges) Reset() {
*x = ReviewChanges{}
if protoimpl.UnsafeEnabled {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[10]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -848,7 +1016,7 @@ func (x *ReviewChanges) String() string {
func (*ReviewChanges) ProtoMessage() {}
func (x *ReviewChanges) ProtoReflect() protoreflect.Message {
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[10]
mi := &file_teleport_accesslist_v1_accesslist_proto_msgTypes[11]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -861,14 +1029,7 @@ func (x *ReviewChanges) ProtoReflect() protoreflect.Message {
// Deprecated: Use ReviewChanges.ProtoReflect.Descriptor instead.
func (*ReviewChanges) Descriptor() ([]byte, []int) {
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{10}
}
func (x *ReviewChanges) GetFrequencyChanged() *durationpb.Duration {
if x != nil {
return x.FrequencyChanged
}
return nil
return file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP(), []int{11}
}
func (x *ReviewChanges) GetMembershipRequirementsChanged() *AccessListRequires {
@@ -885,6 +1046,20 @@ func (x *ReviewChanges) GetRemovedMembers() []string {
return nil
}
func (x *ReviewChanges) GetReviewFrequencyChanged() ReviewFrequency {
if x != nil {
return x.ReviewFrequencyChanged
}
return ReviewFrequency_REVIEW_FREQUENCY_UNSPECIFIED
}
func (x *ReviewChanges) GetReviewDayOfMonthChanged() ReviewDayOfMonth {
if x != nil {
return x.ReviewDayOfMonthChanged
}
return ReviewDayOfMonth_REVIEW_DAY_OF_MONTH_UNSPECIFIED
}
var File_teleport_accesslist_v1_accesslist_proto protoreflect.FileDescriptor
var file_teleport_accesslist_v1_accesslist_proto_rawDesc = []byte{
@@ -892,9 +1067,7 @@ var file_teleport_accesslist_v1_accesslist_proto_rawDesc = []byte{
0x73, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c,
0x69, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x74, 0x65, 0x6c, 0x65, 0x70,
0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76,
0x31, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x1a, 0x27, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x68, 0x65, 0x61,
0x64, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x68,
@@ -948,111 +1121,154 @@ var file_teleport_accesslist_v1_accesslist_proto_rawDesc = []byte{
0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74,
0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x52, 0x10, 0x69, 0x6e, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65,
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x0f, 0x41, 0x63, 0x63, 0x65, 0x73,
0x73, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x12, 0x37, 0x0a, 0x09, 0x66, 0x72,
0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65,
0x6e, 0x63, 0x79, 0x12, 0x42, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x61, 0x75, 0x64, 0x69,
0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x41, 0x75,
0x64, 0x69, 0x74, 0x44, 0x61, 0x74, 0x65, 0x22, 0x5c, 0x0a, 0x12, 0x41, 0x63, 0x63, 0x65, 0x73,
0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x12, 0x14, 0x0a,
0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f,
0x6c, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74,
0x72, 0x61, 0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x69, 0x74, 0x52, 0x06, 0x74,
0x72, 0x61, 0x69, 0x74, 0x73, 0x22, 0x5a, 0x0a, 0x10, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c,
0x69, 0x73, 0x74, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x6c,
0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x12,
0x30, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x18, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x61, 0x69, 0x74,
0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x69, 0x74, 0x52, 0x06, 0x74, 0x72, 0x61, 0x69, 0x74,
0x73, 0x22, 0x7c, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x06, 0x68,
0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52,
0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x36, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4d,
0x65, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22,
0xb5, 0x02, 0x0a, 0x0a, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1f,
0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12,
0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
0x61, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x6a, 0x6f, 0x69, 0x6e, 0x65, 0x64, 0x18, 0x03, 0x20,
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xaa, 0x01, 0x0a, 0x0f, 0x41, 0x63, 0x63, 0x65, 0x73,
0x73, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x12, 0x42, 0x0a, 0x0f, 0x6e, 0x65,
0x78, 0x74, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
0x06, 0x6a, 0x6f, 0x69, 0x6e, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72,
0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x12, 0x16, 0x0a,
0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72,
0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x62,
0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x65, 0x64, 0x42, 0x79,
0x12, 0x55, 0x0a, 0x11, 0x69, 0x6e, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x73,
0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73,
0x74, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, 0x53,
0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x10, 0x69, 0x6e, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c,
0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x7c, 0x0a, 0x06, 0x52, 0x65, 0x76, 0x69, 0x65,
0x77, 0x12, 0x3a, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61,
0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48,
0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x36, 0x0a,
0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65,
0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73,
0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x53, 0x70, 0x65, 0x63, 0x52,
0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0xdf, 0x01, 0x0a, 0x0a, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77,
0x53, 0x70, 0x65, 0x63, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c,
0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73,
0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x65,
0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77,
0x65, 0x72, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x64, 0x61,
0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44, 0x61, 0x74, 0x65,
0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f,
0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31,
0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x07,
0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x22, 0xf4, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x76, 0x69,
0x65, 0x77, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x46, 0x0a, 0x11, 0x66, 0x72, 0x65,
0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52,
0x10, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
0x64, 0x12, 0x72, 0x0a, 0x1f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f,
0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x5f, 0x63, 0x68, 0x61,
0x6e, 0x67, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x65, 0x6c,
0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74,
0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x52, 0x1d, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x68,
0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x43, 0x68,
0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64,
0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e,
0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x2a, 0xc6,
0x01, 0x0a, 0x10, 0x49, 0x6e, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x61,
0x74, 0x75, 0x73, 0x12, 0x21, 0x0a, 0x1d, 0x49, 0x4e, 0x45, 0x4c, 0x49, 0x47, 0x49, 0x42, 0x4c,
0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x49, 0x4e, 0x45, 0x4c, 0x49, 0x47,
0x49, 0x42, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x4c, 0x49, 0x47,
0x49, 0x42, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x49, 0x4e, 0x45, 0x4c, 0x49, 0x47,
0x49, 0x42, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x53, 0x45, 0x52,
0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x45, 0x58, 0x49, 0x53, 0x54, 0x10, 0x02, 0x12, 0x2a, 0x0a, 0x26,
0x49, 0x4e, 0x45, 0x4c, 0x49, 0x47, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55,
0x53, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52,
0x45, 0x4d, 0x45, 0x4e, 0x54, 0x53, 0x10, 0x03, 0x12, 0x1d, 0x0a, 0x19, 0x49, 0x4e, 0x45, 0x4c,
0x49, 0x47, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x58,
0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x04, 0x42, 0x58, 0x5a, 0x56, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69,
0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65,
0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73,
0x74, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x76,
0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x0d, 0x6e, 0x65, 0x78, 0x74, 0x41, 0x75, 0x64, 0x69, 0x74, 0x44, 0x61, 0x74, 0x65, 0x12, 0x42,
0x0a, 0x0a, 0x72, 0x65, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63,
0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x75,
0x72, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0a, 0x72, 0x65, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
0x63, 0x65, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65,
0x6e, 0x63, 0x79, 0x22, 0x9f, 0x01, 0x0a, 0x0a, 0x52, 0x65, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
0x63, 0x65, 0x12, 0x45, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52,
0x65, 0x76, 0x69, 0x65, 0x77, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x09,
0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x4a, 0x0a, 0x0c, 0x64, 0x61, 0x79,
0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73,
0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44,
0x61, 0x79, 0x4f, 0x66, 0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x52, 0x0a, 0x64, 0x61, 0x79, 0x4f, 0x66,
0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x22, 0x5c, 0x0a, 0x12, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c,
0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x72,
0x6f, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65,
0x73, 0x12, 0x30, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x18, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x61,
0x69, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x69, 0x74, 0x52, 0x06, 0x74, 0x72, 0x61,
0x69, 0x74, 0x73, 0x22, 0x5a, 0x0a, 0x10, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73,
0x74, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73,
0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x30, 0x0a,
0x06, 0x74, 0x72, 0x61, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e,
0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x74, 0x72, 0x61, 0x69, 0x74, 0x2e, 0x76,
0x31, 0x2e, 0x54, 0x72, 0x61, 0x69, 0x74, 0x52, 0x06, 0x74, 0x72, 0x61, 0x69, 0x74, 0x73, 0x22,
0x7c, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x06, 0x68, 0x65, 0x61,
0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52,
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06, 0x68,
0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x36, 0x0a, 0x04, 0x73, 0x70, 0x65, 0x63, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61,
0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x65, 0x6d,
0x62, 0x65, 0x72, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0xb5, 0x02,
0x0a, 0x0a, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1f, 0x0a, 0x0b,
0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x12, 0x0a,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x12, 0x32, 0x0a, 0x06, 0x6a, 0x6f, 0x69, 0x6e, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x6a,
0x6f, 0x69, 0x6e, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73,
0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x52, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72,
0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61,
0x73, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18,
0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x65, 0x64, 0x42, 0x79, 0x12, 0x55,
0x0a, 0x11, 0x69, 0x6e, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x73, 0x74, 0x61,
0x74, 0x75, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e,
0x76, 0x31, 0x2e, 0x49, 0x6e, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x61,
0x74, 0x75, 0x73, 0x52, 0x10, 0x69, 0x6e, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, 0x53,
0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x7c, 0x0a, 0x06, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12,
0x3a, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65,
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x48, 0x65, 0x61,
0x64, 0x65, 0x72, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x36, 0x0a, 0x04, 0x73,
0x70, 0x65, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x65, 0x6c, 0x65,
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e,
0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73,
0x70, 0x65, 0x63, 0x22, 0xdf, 0x01, 0x0a, 0x0a, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x53, 0x70,
0x65, 0x63, 0x12, 0x1f, 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6c, 0x69, 0x73,
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c,
0x69, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72, 0x73,
0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x65, 0x72,
0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x64, 0x61, 0x74, 0x65,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x52, 0x0a, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44, 0x61, 0x74, 0x65, 0x12, 0x14,
0x0a, 0x05, 0x6e, 0x6f, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6e,
0x6f, 0x74, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18,
0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74,
0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52,
0x65, 0x76, 0x69, 0x65, 0x77, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x07, 0x63, 0x68,
0x61, 0x6e, 0x67, 0x65, 0x73, 0x22, 0x90, 0x03, 0x0a, 0x0d, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77,
0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x72, 0x0a, 0x1f, 0x6d, 0x65, 0x6d, 0x62, 0x65,
0x72, 0x73, 0x68, 0x69, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e,
0x74, 0x73, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x2a, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65,
0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73,
0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x52, 0x1d, 0x6d, 0x65,
0x6d, 0x62, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x72,
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x18, 0x03,
0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x4d, 0x65, 0x6d,
0x62, 0x65, 0x72, 0x73, 0x12, 0x61, 0x0a, 0x18, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x5f, 0x66,
0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64,
0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72,
0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e,
0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x52,
0x16, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79,
0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x66, 0x0a, 0x1b, 0x72, 0x65, 0x76, 0x69, 0x65,
0x77, 0x5f, 0x64, 0x61, 0x79, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x5f, 0x63,
0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x74,
0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69,
0x73, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44, 0x61, 0x79, 0x4f,
0x66, 0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x52, 0x17, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44, 0x61,
0x79, 0x4f, 0x66, 0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x4a,
0x04, 0x08, 0x01, 0x10, 0x02, 0x52, 0x11, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79,
0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x2a, 0xb6, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x76,
0x69, 0x65, 0x77, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x20, 0x0a, 0x1c,
0x52, 0x45, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x46, 0x52, 0x45, 0x51, 0x55, 0x45, 0x4e, 0x43, 0x59,
0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1e,
0x0a, 0x1a, 0x52, 0x45, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x46, 0x52, 0x45, 0x51, 0x55, 0x45, 0x4e,
0x43, 0x59, 0x5f, 0x4f, 0x4e, 0x45, 0x5f, 0x4d, 0x4f, 0x4e, 0x54, 0x48, 0x10, 0x01, 0x12, 0x21,
0x0a, 0x1d, 0x52, 0x45, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x46, 0x52, 0x45, 0x51, 0x55, 0x45, 0x4e,
0x43, 0x59, 0x5f, 0x54, 0x48, 0x52, 0x45, 0x45, 0x5f, 0x4d, 0x4f, 0x4e, 0x54, 0x48, 0x53, 0x10,
0x03, 0x12, 0x1f, 0x0a, 0x1b, 0x52, 0x45, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x46, 0x52, 0x45, 0x51,
0x55, 0x45, 0x4e, 0x43, 0x59, 0x5f, 0x53, 0x49, 0x58, 0x5f, 0x4d, 0x4f, 0x4e, 0x54, 0x48, 0x53,
0x10, 0x06, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x46, 0x52, 0x45,
0x51, 0x55, 0x45, 0x4e, 0x43, 0x59, 0x5f, 0x4f, 0x4e, 0x45, 0x5f, 0x59, 0x45, 0x41, 0x52, 0x10,
0x0c, 0x2a, 0x97, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x44, 0x61, 0x79, 0x4f,
0x66, 0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x12, 0x23, 0x0a, 0x1f, 0x52, 0x45, 0x56, 0x49, 0x45, 0x57,
0x5f, 0x44, 0x41, 0x59, 0x5f, 0x4f, 0x46, 0x5f, 0x4d, 0x4f, 0x4e, 0x54, 0x48, 0x5f, 0x55, 0x4e,
0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x52,
0x45, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x44, 0x41, 0x59, 0x5f, 0x4f, 0x46, 0x5f, 0x4d, 0x4f, 0x4e,
0x54, 0x48, 0x5f, 0x46, 0x49, 0x52, 0x53, 0x54, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x52, 0x45,
0x56, 0x49, 0x45, 0x57, 0x5f, 0x44, 0x41, 0x59, 0x5f, 0x4f, 0x46, 0x5f, 0x4d, 0x4f, 0x4e, 0x54,
0x48, 0x5f, 0x46, 0x49, 0x46, 0x54, 0x45, 0x45, 0x4e, 0x54, 0x48, 0x10, 0x0f, 0x12, 0x1c, 0x0a,
0x18, 0x52, 0x45, 0x56, 0x49, 0x45, 0x57, 0x5f, 0x44, 0x41, 0x59, 0x5f, 0x4f, 0x46, 0x5f, 0x4d,
0x4f, 0x4e, 0x54, 0x48, 0x5f, 0x4c, 0x41, 0x53, 0x54, 0x10, 0x1f, 0x2a, 0xc6, 0x01, 0x0a, 0x10,
0x49, 0x6e, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x12, 0x21, 0x0a, 0x1d, 0x49, 0x4e, 0x45, 0x4c, 0x49, 0x47, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x53,
0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45,
0x44, 0x10, 0x00, 0x12, 0x1e, 0x0a, 0x1a, 0x49, 0x4e, 0x45, 0x4c, 0x49, 0x47, 0x49, 0x42, 0x4c,
0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x4c, 0x49, 0x47, 0x49, 0x42, 0x4c,
0x45, 0x10, 0x01, 0x12, 0x24, 0x0a, 0x20, 0x49, 0x4e, 0x45, 0x4c, 0x49, 0x47, 0x49, 0x42, 0x4c,
0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x4e, 0x4f,
0x54, 0x5f, 0x45, 0x58, 0x49, 0x53, 0x54, 0x10, 0x02, 0x12, 0x2a, 0x0a, 0x26, 0x49, 0x4e, 0x45,
0x4c, 0x49, 0x47, 0x49, 0x42, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4d,
0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x4d, 0x45,
0x4e, 0x54, 0x53, 0x10, 0x03, 0x12, 0x1d, 0x0a, 0x19, 0x49, 0x4e, 0x45, 0x4c, 0x49, 0x47, 0x49,
0x42, 0x4c, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52,
0x45, 0x44, 0x10, 0x04, 0x42, 0x58, 0x5a, 0x56, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c,
0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65,
0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70,
0x6f, 0x72, 0x74, 0x2f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x2f, 0x76,
0x31, 0x3b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6c, 0x69, 0x73, 0x74, 0x76, 0x31, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -1067,55 +1283,60 @@ func file_teleport_accesslist_v1_accesslist_proto_rawDescGZIP() []byte {
return file_teleport_accesslist_v1_accesslist_proto_rawDescData
}
var file_teleport_accesslist_v1_accesslist_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_teleport_accesslist_v1_accesslist_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
var file_teleport_accesslist_v1_accesslist_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
var file_teleport_accesslist_v1_accesslist_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
var file_teleport_accesslist_v1_accesslist_proto_goTypes = []interface{}{
(IneligibleStatus)(0), // 0: teleport.accesslist.v1.IneligibleStatus
(*AccessList)(nil), // 1: teleport.accesslist.v1.AccessList
(*AccessListSpec)(nil), // 2: teleport.accesslist.v1.AccessListSpec
(*AccessListOwner)(nil), // 3: teleport.accesslist.v1.AccessListOwner
(*AccessListAudit)(nil), // 4: teleport.accesslist.v1.AccessListAudit
(*AccessListRequires)(nil), // 5: teleport.accesslist.v1.AccessListRequires
(*AccessListGrants)(nil), // 6: teleport.accesslist.v1.AccessListGrants
(*Member)(nil), // 7: teleport.accesslist.v1.Member
(*MemberSpec)(nil), // 8: teleport.accesslist.v1.MemberSpec
(*Review)(nil), // 9: teleport.accesslist.v1.Review
(*ReviewSpec)(nil), // 10: teleport.accesslist.v1.ReviewSpec
(*ReviewChanges)(nil), // 11: teleport.accesslist.v1.ReviewChanges
(*v1.ResourceHeader)(nil), // 12: teleport.header.v1.ResourceHeader
(*durationpb.Duration)(nil), // 13: google.protobuf.Duration
(*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp
(*v11.Trait)(nil), // 15: teleport.trait.v1.Trait
(ReviewFrequency)(0), // 0: teleport.accesslist.v1.ReviewFrequency
(ReviewDayOfMonth)(0), // 1: teleport.accesslist.v1.ReviewDayOfMonth
(IneligibleStatus)(0), // 2: teleport.accesslist.v1.IneligibleStatus
(*AccessList)(nil), // 3: teleport.accesslist.v1.AccessList
(*AccessListSpec)(nil), // 4: teleport.accesslist.v1.AccessListSpec
(*AccessListOwner)(nil), // 5: teleport.accesslist.v1.AccessListOwner
(*AccessListAudit)(nil), // 6: teleport.accesslist.v1.AccessListAudit
(*Recurrence)(nil), // 7: teleport.accesslist.v1.Recurrence
(*AccessListRequires)(nil), // 8: teleport.accesslist.v1.AccessListRequires
(*AccessListGrants)(nil), // 9: teleport.accesslist.v1.AccessListGrants
(*Member)(nil), // 10: teleport.accesslist.v1.Member
(*MemberSpec)(nil), // 11: teleport.accesslist.v1.MemberSpec
(*Review)(nil), // 12: teleport.accesslist.v1.Review
(*ReviewSpec)(nil), // 13: teleport.accesslist.v1.ReviewSpec
(*ReviewChanges)(nil), // 14: teleport.accesslist.v1.ReviewChanges
(*v1.ResourceHeader)(nil), // 15: teleport.header.v1.ResourceHeader
(*timestamppb.Timestamp)(nil), // 16: google.protobuf.Timestamp
(*v11.Trait)(nil), // 17: teleport.trait.v1.Trait
}
var file_teleport_accesslist_v1_accesslist_proto_depIdxs = []int32{
12, // 0: teleport.accesslist.v1.AccessList.header:type_name -> teleport.header.v1.ResourceHeader
2, // 1: teleport.accesslist.v1.AccessList.spec:type_name -> teleport.accesslist.v1.AccessListSpec
3, // 2: teleport.accesslist.v1.AccessListSpec.owners:type_name -> teleport.accesslist.v1.AccessListOwner
4, // 3: teleport.accesslist.v1.AccessListSpec.audit:type_name -> teleport.accesslist.v1.AccessListAudit
5, // 4: teleport.accesslist.v1.AccessListSpec.membership_requires:type_name -> teleport.accesslist.v1.AccessListRequires
5, // 5: teleport.accesslist.v1.AccessListSpec.ownership_requires:type_name -> teleport.accesslist.v1.AccessListRequires
6, // 6: teleport.accesslist.v1.AccessListSpec.grants:type_name -> teleport.accesslist.v1.AccessListGrants
0, // 7: teleport.accesslist.v1.AccessListOwner.ineligible_status:type_name -> teleport.accesslist.v1.IneligibleStatus
13, // 8: teleport.accesslist.v1.AccessListAudit.frequency:type_name -> google.protobuf.Duration
14, // 9: teleport.accesslist.v1.AccessListAudit.next_audit_date:type_name -> google.protobuf.Timestamp
15, // 10: teleport.accesslist.v1.AccessListRequires.traits:type_name -> teleport.trait.v1.Trait
15, // 11: teleport.accesslist.v1.AccessListGrants.traits:type_name -> teleport.trait.v1.Trait
12, // 12: teleport.accesslist.v1.Member.header:type_name -> teleport.header.v1.ResourceHeader
8, // 13: teleport.accesslist.v1.Member.spec:type_name -> teleport.accesslist.v1.MemberSpec
14, // 14: teleport.accesslist.v1.MemberSpec.joined:type_name -> google.protobuf.Timestamp
14, // 15: teleport.accesslist.v1.MemberSpec.expires:type_name -> google.protobuf.Timestamp
0, // 16: teleport.accesslist.v1.MemberSpec.ineligible_status:type_name -> teleport.accesslist.v1.IneligibleStatus
12, // 17: teleport.accesslist.v1.Review.header:type_name -> teleport.header.v1.ResourceHeader
10, // 18: teleport.accesslist.v1.Review.spec:type_name -> teleport.accesslist.v1.ReviewSpec
14, // 19: teleport.accesslist.v1.ReviewSpec.review_date:type_name -> google.protobuf.Timestamp
11, // 20: teleport.accesslist.v1.ReviewSpec.changes:type_name -> teleport.accesslist.v1.ReviewChanges
13, // 21: teleport.accesslist.v1.ReviewChanges.frequency_changed:type_name -> google.protobuf.Duration
5, // 22: teleport.accesslist.v1.ReviewChanges.membership_requirements_changed:type_name -> teleport.accesslist.v1.AccessListRequires
23, // [23:23] is the sub-list for method output_type
23, // [23:23] is the sub-list for method input_type
23, // [23:23] is the sub-list for extension type_name
23, // [23:23] is the sub-list for extension extendee
0, // [0:23] is the sub-list for field type_name
15, // 0: teleport.accesslist.v1.AccessList.header:type_name -> teleport.header.v1.ResourceHeader
4, // 1: teleport.accesslist.v1.AccessList.spec:type_name -> teleport.accesslist.v1.AccessListSpec
5, // 2: teleport.accesslist.v1.AccessListSpec.owners:type_name -> teleport.accesslist.v1.AccessListOwner
6, // 3: teleport.accesslist.v1.AccessListSpec.audit:type_name -> teleport.accesslist.v1.AccessListAudit
8, // 4: teleport.accesslist.v1.AccessListSpec.membership_requires:type_name -> teleport.accesslist.v1.AccessListRequires
8, // 5: teleport.accesslist.v1.AccessListSpec.ownership_requires:type_name -> teleport.accesslist.v1.AccessListRequires
9, // 6: teleport.accesslist.v1.AccessListSpec.grants:type_name -> teleport.accesslist.v1.AccessListGrants
2, // 7: teleport.accesslist.v1.AccessListOwner.ineligible_status:type_name -> teleport.accesslist.v1.IneligibleStatus
16, // 8: teleport.accesslist.v1.AccessListAudit.next_audit_date:type_name -> google.protobuf.Timestamp
7, // 9: teleport.accesslist.v1.AccessListAudit.recurrence:type_name -> teleport.accesslist.v1.Recurrence
0, // 10: teleport.accesslist.v1.Recurrence.frequency:type_name -> teleport.accesslist.v1.ReviewFrequency
1, // 11: teleport.accesslist.v1.Recurrence.day_of_month:type_name -> teleport.accesslist.v1.ReviewDayOfMonth
17, // 12: teleport.accesslist.v1.AccessListRequires.traits:type_name -> teleport.trait.v1.Trait
17, // 13: teleport.accesslist.v1.AccessListGrants.traits:type_name -> teleport.trait.v1.Trait
15, // 14: teleport.accesslist.v1.Member.header:type_name -> teleport.header.v1.ResourceHeader
11, // 15: teleport.accesslist.v1.Member.spec:type_name -> teleport.accesslist.v1.MemberSpec
16, // 16: teleport.accesslist.v1.MemberSpec.joined:type_name -> google.protobuf.Timestamp
16, // 17: teleport.accesslist.v1.MemberSpec.expires:type_name -> google.protobuf.Timestamp
2, // 18: teleport.accesslist.v1.MemberSpec.ineligible_status:type_name -> teleport.accesslist.v1.IneligibleStatus
15, // 19: teleport.accesslist.v1.Review.header:type_name -> teleport.header.v1.ResourceHeader
13, // 20: teleport.accesslist.v1.Review.spec:type_name -> teleport.accesslist.v1.ReviewSpec
16, // 21: teleport.accesslist.v1.ReviewSpec.review_date:type_name -> google.protobuf.Timestamp
14, // 22: teleport.accesslist.v1.ReviewSpec.changes:type_name -> teleport.accesslist.v1.ReviewChanges
8, // 23: teleport.accesslist.v1.ReviewChanges.membership_requirements_changed:type_name -> teleport.accesslist.v1.AccessListRequires
0, // 24: teleport.accesslist.v1.ReviewChanges.review_frequency_changed:type_name -> teleport.accesslist.v1.ReviewFrequency
1, // 25: teleport.accesslist.v1.ReviewChanges.review_day_of_month_changed:type_name -> teleport.accesslist.v1.ReviewDayOfMonth
26, // [26:26] is the sub-list for method output_type
26, // [26:26] is the sub-list for method input_type
26, // [26:26] is the sub-list for extension type_name
26, // [26:26] is the sub-list for extension extendee
0, // [0:26] is the sub-list for field type_name
}
func init() { file_teleport_accesslist_v1_accesslist_proto_init() }
@@ -1173,7 +1394,7 @@ func file_teleport_accesslist_v1_accesslist_proto_init() {
}
}
file_teleport_accesslist_v1_accesslist_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AccessListRequires); i {
switch v := v.(*Recurrence); i {
case 0:
return &v.state
case 1:
@@ -1185,7 +1406,7 @@ func file_teleport_accesslist_v1_accesslist_proto_init() {
}
}
file_teleport_accesslist_v1_accesslist_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*AccessListGrants); i {
switch v := v.(*AccessListRequires); i {
case 0:
return &v.state
case 1:
@@ -1197,7 +1418,7 @@ func file_teleport_accesslist_v1_accesslist_proto_init() {
}
}
file_teleport_accesslist_v1_accesslist_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Member); i {
switch v := v.(*AccessListGrants); i {
case 0:
return &v.state
case 1:
@@ -1209,7 +1430,7 @@ func file_teleport_accesslist_v1_accesslist_proto_init() {
}
}
file_teleport_accesslist_v1_accesslist_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MemberSpec); i {
switch v := v.(*Member); i {
case 0:
return &v.state
case 1:
@@ -1221,7 +1442,7 @@ func file_teleport_accesslist_v1_accesslist_proto_init() {
}
}
file_teleport_accesslist_v1_accesslist_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Review); i {
switch v := v.(*MemberSpec); i {
case 0:
return &v.state
case 1:
@@ -1233,7 +1454,7 @@ func file_teleport_accesslist_v1_accesslist_proto_init() {
}
}
file_teleport_accesslist_v1_accesslist_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReviewSpec); i {
switch v := v.(*Review); i {
case 0:
return &v.state
case 1:
@@ -1245,6 +1466,18 @@ func file_teleport_accesslist_v1_accesslist_proto_init() {
}
}
file_teleport_accesslist_v1_accesslist_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReviewSpec); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_teleport_accesslist_v1_accesslist_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReviewChanges); i {
case 0:
return &v.state
@@ -1262,8 +1495,8 @@ func file_teleport_accesslist_v1_accesslist_proto_init() {
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_teleport_accesslist_v1_accesslist_proto_rawDesc,
NumEnums: 1,
NumMessages: 11,
NumEnums: 3,
NumMessages: 12,
NumExtensions: 0,
NumServices: 0,
},
@@ -16,7 +16,6 @@ syntax = "proto3";
package teleport.accesslist.v1;
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
import "teleport/header/v1/resourceheader.proto";
import "teleport/trait/v1/trait.proto";
@@ -80,11 +79,40 @@ message AccessListOwner {
// AccessListAudit describes the audit configuration for an access list.
message AccessListAudit {
// frequency is a duration that describes how often an access list must be audited.
google.protobuf.Duration frequency = 1;
reserved 1;
reserved "frequency";
// next_audit_date is when the next audit date should be done by.
google.protobuf.Timestamp next_audit_date = 2;
// recurrence is the recurrence definition
Recurrence recurrence = 3;
}
// ReviewFrequency is the frequency of reviews.
enum ReviewFrequency {
REVIEW_FREQUENCY_UNSPECIFIED = 0;
REVIEW_FREQUENCY_ONE_MONTH = 1;
REVIEW_FREQUENCY_THREE_MONTHS = 3;
REVIEW_FREQUENCY_SIX_MONTHS = 6;
REVIEW_FREQUENCY_ONE_YEAR = 12;
}
// ReviewDayOfMonth is the day of month that reviews will repeat on.
enum ReviewDayOfMonth {
REVIEW_DAY_OF_MONTH_UNSPECIFIED = 0;
REVIEW_DAY_OF_MONTH_FIRST = 1;
REVIEW_DAY_OF_MONTH_FIFTEENTH = 15;
REVIEW_DAY_OF_MONTH_LAST = 31;
}
// Recurrence is the definition for when reviews will be scheduled.
message Recurrence {
// frequency is the frequency of reviews.
ReviewFrequency frequency = 1;
// day_of_month is the day of month that reviews will be scheduled on.
ReviewDayOfMonth day_of_month = 2;
}
// AccessListRequires describes a requirement section for an access list. A user must
@@ -187,12 +215,18 @@ message ReviewSpec {
// ReviewChanges are the changes that were made as part of the review.
message ReviewChanges {
// audit_frequency_changed is populated if the audit frequency was changed.
google.protobuf.Duration frequency_changed = 1;
reserved 1;
reserved "frequency_changed";
// membership_requirements_changed is populated if the requirements were changed as part of this review.
AccessListRequires membership_requirements_changed = 2;
// removed_members contains the members that were removed as part of this review.
repeated string removed_members = 3;
// review_frequency_changed is populated if the review frequency has changed.
ReviewFrequency review_frequency_changed = 4;
// review_day_of_month changed is populated if the review day of month has changed.
ReviewDayOfMonth review_day_of_month_changed = 5;
}
+145 -18
View File
@@ -18,6 +18,7 @@ package accesslist
import (
"encoding/json"
"strings"
"time"
"github.com/gravitational/trace"
@@ -29,6 +30,85 @@ import (
"github.com/gravitational/teleport/api/utils"
)
// ReviewFrequency is the review frequency in months.
type ReviewFrequency int
const (
OneMonth ReviewFrequency = 1
ThreeMonths ReviewFrequency = 3
SixMonths ReviewFrequency = 6
OneYear ReviewFrequency = 12
)
func (r ReviewFrequency) String() string {
switch r {
case OneMonth:
return "1 month"
case ThreeMonths:
return "3 months"
case SixMonths:
return "6 months"
case OneYear:
return "1 year"
}
return ""
}
func parseReviewFrequency(input string) ReviewFrequency {
lowerInput := strings.ReplaceAll(strings.ToLower(input), " ", "")
switch lowerInput {
case "1month", "1months", "1m", "1":
return OneMonth
case "3month", "3months", "3m", "3":
return ThreeMonths
case "6month", "6months", "6m", "6":
return SixMonths
case "12month", "12months", "12m", "12", "1years", "1year", "1y":
return OneYear
}
// We won't return an error here and we'll just let CheckAndSetDefaults handle the rest.
return 0
}
// ReviewDayOfMonth is the day of month the review should be repeated on.
type ReviewDayOfMonth int
const (
FirstDayOfMonth ReviewDayOfMonth = 1
FifteenthDayOfMonth ReviewDayOfMonth = 15
LastDayOfMonth ReviewDayOfMonth = 31
)
func (r ReviewDayOfMonth) String() string {
switch r {
case FirstDayOfMonth:
return "1"
case FifteenthDayOfMonth:
return "15"
case LastDayOfMonth:
return "last"
}
return ""
}
func parseReviewDayOfMonth(input string) ReviewDayOfMonth {
lowerInput := strings.ReplaceAll(strings.ToLower(input), " ", "")
switch lowerInput {
case "1", "first":
return FirstDayOfMonth
case "15":
return FifteenthDayOfMonth
case "last":
return LastDayOfMonth
}
// We won't return an error here and we'll just let CheckAndSetDefaults handle the rest.
return 0
}
// AccessList describes the basic building block of access grants, which are
// similar to access requests but for longer lived permissions that need to be
// regularly audited.
@@ -82,11 +162,21 @@ type Owner struct {
// Audit describes the audit configuration for an access list.
type Audit struct {
// Frequency is a duration that describes how often an access list must be audited.
Frequency time.Duration `json:"frequency" yaml:"frequency"`
// NextAuditDate is the date that the next audit should be performed.
NextAuditDate time.Time `json:"next_audit_date" yaml:"next_audit_date"`
// Recurrence is the recurrence definition for auditing. Valid values are
// 1, first, 15, and last.
Recurrence Recurrence `json:"recurrence" yaml:"recurrence"`
}
// Recurrence defines when access list reviews should occur.
type Recurrence struct {
// Frequency is the frequency between access list reviews.
Frequency ReviewFrequency `json:"frequency" yaml:"frequency"`
// DayOfMonth is the day of month subsequent reviews will be scheduled on.
DayOfMonth ReviewDayOfMonth `json:"day_of_month" yaml:"day_of_month"`
}
// Requires describes a requirement section for an access list. A user must
@@ -157,11 +247,29 @@ func (a *AccessList) CheckAndSetDefaults() error {
return trace.BadParameter("owners are missing")
}
if a.Spec.Audit.Frequency == 0 {
return trace.BadParameter("audit frequency must be greater than 0")
if a.Spec.Audit.NextAuditDate.IsZero() {
return trace.BadParameter("next audit date is missing")
}
// TODO(mdwn): Next audit date must not be zero.
if a.Spec.Audit.Recurrence.Frequency == 0 {
a.Spec.Audit.Recurrence.Frequency = SixMonths
}
switch a.Spec.Audit.Recurrence.Frequency {
case OneMonth, ThreeMonths, SixMonths, OneYear:
default:
return trace.BadParameter("recurrence frequency is an invalid value")
}
if a.Spec.Audit.Recurrence.DayOfMonth == 0 {
a.Spec.Audit.Recurrence.DayOfMonth = FirstDayOfMonth
}
switch a.Spec.Audit.Recurrence.DayOfMonth {
case FirstDayOfMonth, FifteenthDayOfMonth, LastDayOfMonth:
default:
return trace.BadParameter("recurrence day of month is an invalid value")
}
if len(a.Spec.Grants.Roles) == 0 && len(a.Spec.Grants.Traits) == 0 {
return trace.BadParameter("grants must specify at least one role or trait")
@@ -199,11 +307,6 @@ func (a *AccessList) SetOwners(owners []Owner) {
a.Spec.Owners = owners
}
// GetAuditFrequency returns the audit frequency from the access list.
func (a *AccessList) GetAuditFrequency() time.Duration {
return a.Spec.Audit.Frequency
}
// GetMembershipRequires returns the membership requires configuration from the access list.
func (a *AccessList) GetMembershipRequires() Requires {
return a.Spec.MembershipRequires
@@ -242,7 +345,6 @@ func (a *AccessList) CloneResource() types.ResourceWithLabels {
func (a *Audit) UnmarshalJSON(data []byte) error {
type Alias Audit
audit := struct {
Frequency string `json:"frequency"`
NextAuditDate string `json:"next_audit_date"`
*Alias
}{
@@ -253,10 +355,6 @@ func (a *Audit) UnmarshalJSON(data []byte) error {
}
var err error
a.Frequency, err = time.ParseDuration(audit.Frequency)
if err != nil {
return trace.Wrap(err)
}
a.NextAuditDate, err = time.Parse(time.RFC3339Nano, audit.NextAuditDate)
if err != nil {
return trace.Wrap(err)
@@ -267,12 +365,41 @@ func (a *Audit) UnmarshalJSON(data []byte) error {
func (a Audit) MarshalJSON() ([]byte, error) {
type Alias Audit
return json.Marshal(&struct {
Frequency string `json:"frequency"`
NextAuditDate string `json:"next_audit_date"`
Alias
}{
Alias: (Alias)(a),
Frequency: a.Frequency.String(),
NextAuditDate: a.NextAuditDate.Format(time.RFC3339Nano),
})
}
func (r *Recurrence) UnmarshalJSON(data []byte) error {
type Alias Recurrence
recurrence := struct {
Frequency string `json:"frequency"`
DayOfMonth string `json:"day_of_month"`
*Alias
}{
Alias: (*Alias)(r),
}
if err := json.Unmarshal(data, &recurrence); err != nil {
return trace.Wrap(err)
}
r.Frequency = parseReviewFrequency(recurrence.Frequency)
r.DayOfMonth = parseReviewDayOfMonth(recurrence.DayOfMonth)
return nil
}
func (r Recurrence) MarshalJSON() ([]byte, error) {
type Alias Recurrence
return json.Marshal(&struct {
Frequency string `json:"frequency"`
DayOfMonth string `json:"day_of_month"`
Alias
}{
Alias: (Alias)(r),
Frequency: r.Frequency.String(),
DayOfMonth: r.DayOfMonth.String(),
})
}
+91 -11
View File
@@ -26,6 +26,85 @@ import (
"github.com/gravitational/teleport/api/types/header"
)
func TestParseReviewFrequency(t *testing.T) {
t.Parallel()
tests := []struct {
input string
expected ReviewFrequency
}{
{input: "1 month", expected: OneMonth},
{input: "1month", expected: OneMonth},
{input: "1months", expected: OneMonth},
{input: "1 m", expected: OneMonth},
{input: "1m", expected: OneMonth},
{input: "1", expected: OneMonth},
{input: "3 month", expected: ThreeMonths},
{input: "3month", expected: ThreeMonths},
{input: "3months", expected: ThreeMonths},
{input: "3 m", expected: ThreeMonths},
{input: "3m", expected: ThreeMonths},
{input: "3", expected: ThreeMonths},
{input: "6 month", expected: SixMonths},
{input: "6month", expected: SixMonths},
{input: "6months", expected: SixMonths},
{input: "6 m", expected: SixMonths},
{input: "6m", expected: SixMonths},
{input: "6", expected: SixMonths},
{input: "12 month", expected: OneYear},
{input: "12month", expected: OneYear},
{input: "12months", expected: OneYear},
{input: "12 m", expected: OneYear},
{input: "12m", expected: OneYear},
{input: "12", expected: OneYear},
{input: "1 year", expected: OneYear},
{input: "1year", expected: OneYear},
{input: "1 y", expected: OneYear},
{input: "1y", expected: OneYear},
{input: "1 MoNtH", expected: OneMonth},
{input: "unknown"},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
t.Parallel()
require.Equal(t, test.expected, parseReviewFrequency(test.input))
})
}
}
func TestParseReviewDayOfMonth(t *testing.T) {
t.Parallel()
tests := []struct {
input string
expected ReviewDayOfMonth
}{
{input: "1", expected: FirstDayOfMonth},
{input: "first", expected: FirstDayOfMonth},
{input: "15", expected: FifteenthDayOfMonth},
{input: "last", expected: LastDayOfMonth},
{input: "FiRSt", expected: FirstDayOfMonth},
{input: "unknown"},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
t.Parallel()
require.Equal(t, test.expected, parseReviewDayOfMonth(test.input))
})
}
}
func TestDeduplicateOwners(t *testing.T) {
accessList, err := NewAccessList(
header.Metadata{
@@ -49,7 +128,7 @@ func TestDeduplicateOwners(t *testing.T) {
},
},
Audit: Audit{
Frequency: time.Hour,
NextAuditDate: time.Now(),
},
MembershipRequires: Requires{
Roles: []string{"mrole1", "mrole2"},
@@ -85,26 +164,26 @@ func TestDeduplicateOwners(t *testing.T) {
func TestAuditMarshaling(t *testing.T) {
audit := Audit{
Frequency: time.Hour,
NextAuditDate: time.Date(2023, 02, 02, 0, 0, 0, 0, time.UTC),
Recurrence: Recurrence{
Frequency: SixMonths,
DayOfMonth: LastDayOfMonth,
},
}
data, err := json.Marshal(&audit)
require.NoError(t, err)
require.Equal(t, `{"frequency":"1h0m0s","next_audit_date":"2023-02-02T00:00:00Z"}`, string(data))
raw := map[string]interface{}{}
require.NoError(t, json.Unmarshal(data, &raw))
require.Equal(t, "1h0m0s", raw["frequency"])
require.Equal(t, "2023-02-02T00:00:00Z", raw["next_audit_date"])
require.Equal(t, `{"next_audit_date":"2023-02-02T00:00:00Z","recurrence":{"frequency":"6 months","day_of_month":"last"}}`, string(data))
}
func TestAuditUnmarshaling(t *testing.T) {
raw := map[string]interface{}{
"frequency": "1h",
"next_audit_date": "2023-02-02T00:00:00Z",
"recurrence": map[string]interface{}{
"frequency": "3 months",
"day_of_month": "1",
},
}
data, err := json.Marshal(&raw)
@@ -113,6 +192,7 @@ func TestAuditUnmarshaling(t *testing.T) {
var audit Audit
require.NoError(t, json.Unmarshal(data, &audit))
require.Equal(t, time.Hour, audit.Frequency)
require.Equal(t, time.Date(2023, 02, 02, 0, 0, 0, 0, time.UTC), audit.NextAuditDate)
require.Equal(t, ThreeMonths, audit.Recurrence.Frequency)
require.Equal(t, FirstDayOfMonth, audit.Recurrence.DayOfMonth)
}
+11 -3
View File
@@ -18,7 +18,6 @@ package v1
import (
"github.com/gravitational/trace"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/timestamppb"
accesslistv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1"
@@ -51,6 +50,12 @@ func FromProto(msg *accesslistv1.AccessList, opts ...AccessListOption) (*accessl
return nil, trace.BadParameter("grants is missing")
}
var recurrence accesslist.Recurrence
if msg.Spec.Audit.Recurrence != nil {
recurrence.Frequency = accesslist.ReviewFrequency(msg.Spec.Audit.Recurrence.Frequency)
recurrence.DayOfMonth = accesslist.ReviewDayOfMonth(msg.Spec.Audit.Recurrence.DayOfMonth)
}
owners := make([]accesslist.Owner, len(msg.Spec.Owners))
for i, owner := range msg.Spec.Owners {
owners[i] = accesslist.Owner{
@@ -67,8 +72,8 @@ func FromProto(msg *accesslistv1.AccessList, opts ...AccessListOption) (*accessl
Description: msg.Spec.Description,
Owners: owners,
Audit: accesslist.Audit{
Frequency: msg.Spec.Audit.Frequency.AsDuration(),
NextAuditDate: msg.Spec.Audit.NextAuditDate.AsTime(),
Recurrence: recurrence,
},
MembershipRequires: accesslist.Requires{
Roles: msg.Spec.MembershipRequires.Roles,
@@ -116,8 +121,11 @@ func ToProto(accessList *accesslist.AccessList) *accesslistv1.AccessList {
Description: accessList.Spec.Description,
Owners: owners,
Audit: &accesslistv1.AccessListAudit{
Frequency: durationpb.New(accessList.Spec.Audit.Frequency),
NextAuditDate: timestamppb.New(accessList.Spec.Audit.NextAuditDate),
Recurrence: &accesslistv1.Recurrence{
Frequency: accesslistv1.ReviewFrequency(accessList.Spec.Audit.Recurrence.Frequency),
DayOfMonth: accesslistv1.ReviewDayOfMonth(accessList.Spec.Audit.Recurrence.DayOfMonth),
},
},
MembershipRequires: &accesslistv1.AccessListRequires{
Roles: accessList.Spec.MembershipRequires.Roles,
@@ -150,7 +150,6 @@ func newAccessList(t *testing.T, name string) *accesslist.AccessList {
},
},
Audit: accesslist.Audit{
Frequency: time.Hour,
NextAuditDate: time.Now(),
},
MembershipRequires: accesslist.Requires{
+16 -9
View File
@@ -20,7 +20,6 @@ import (
"time"
"github.com/gravitational/trace"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/timestamppb"
accesslistv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1"
@@ -48,9 +47,6 @@ func FromReviewProto(msg *accesslistv1.Review) (*accesslist.Review, error) {
var reviewChanges accesslist.ReviewChanges
if msg.Spec.Changes != nil {
if msg.Spec.Changes.FrequencyChanged != nil {
reviewChanges.FrequencyChanged = msg.Spec.Changes.FrequencyChanged.AsDuration()
}
if msg.Spec.Changes.MembershipRequirementsChanged != nil {
reviewChanges.MembershipRequirementsChanged = &accesslist.Requires{
Roles: msg.Spec.Changes.MembershipRequirementsChanged.Roles,
@@ -58,6 +54,8 @@ func FromReviewProto(msg *accesslistv1.Review) (*accesslist.Review, error) {
}
}
reviewChanges.RemovedMembers = msg.Spec.Changes.RemovedMembers
reviewChanges.ReviewFrequencyChanged = accesslist.ReviewFrequency(msg.Spec.Changes.ReviewFrequencyChanged)
reviewChanges.ReviewDayOfMonthChanged = accesslist.ReviewDayOfMonth(msg.Spec.Changes.ReviewDayOfMonthChanged)
}
member, err := accesslist.NewReview(headerv1.FromMetadataProto(msg.Header.Metadata), accesslist.ReviewSpec{
@@ -77,11 +75,6 @@ func FromReviewProto(msg *accesslistv1.Review) (*accesslist.Review, error) {
// ToReviewProto converts an internal access list review into a v1 access list review object.
func ToReviewProto(review *accesslist.Review) *accesslistv1.Review {
var reviewChanges *accesslistv1.ReviewChanges
if review.Spec.Changes.FrequencyChanged > 0 {
reviewChanges = &accesslistv1.ReviewChanges{
FrequencyChanged: durationpb.New(review.Spec.Changes.FrequencyChanged),
}
}
if review.Spec.Changes.MembershipRequirementsChanged != nil {
if reviewChanges == nil {
reviewChanges = &accesslistv1.ReviewChanges{}
@@ -99,6 +92,20 @@ func ToReviewProto(review *accesslist.Review) *accesslistv1.Review {
reviewChanges.RemovedMembers = review.Spec.Changes.RemovedMembers
}
if review.Spec.Changes.ReviewFrequencyChanged > 0 {
if reviewChanges == nil {
reviewChanges = &accesslistv1.ReviewChanges{}
}
reviewChanges.ReviewFrequencyChanged = accesslistv1.ReviewFrequency(review.Spec.Changes.ReviewFrequencyChanged)
}
if review.Spec.Changes.ReviewDayOfMonthChanged > 0 {
if reviewChanges == nil {
reviewChanges = &accesslistv1.ReviewChanges{}
}
reviewChanges.ReviewDayOfMonthChanged = accesslistv1.ReviewDayOfMonth(review.Spec.Changes.ReviewDayOfMonthChanged)
}
return &accesslistv1.Review{
Header: headerv1.ToResourceHeaderProto(review.ResourceHeader),
+51 -20
View File
@@ -23,6 +23,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/require"
accesslistv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1"
"github.com/gravitational/teleport/api/types/accesslist"
"github.com/gravitational/teleport/api/types/header"
"github.com/gravitational/teleport/api/types/trait"
@@ -90,10 +91,6 @@ func TestReviewFromProtoNils(t *testing.T) {
_, err = FromReviewProto(review)
require.NoError(t, err)
// FrequencyChanged is nil
review = ToReviewProto(newAccessListReview(t, "access-list-review"))
review.Spec.Changes.FrequencyChanged = nil
_, err = FromReviewProto(review)
require.NoError(t, err)
@@ -110,6 +107,20 @@ func TestReviewFromProtoNils(t *testing.T) {
_, err = FromReviewProto(review)
require.NoError(t, err)
// ReviewFrequencyChanged is nil
review = ToReviewProto(newAccessListReview(t, "access-list-review"))
review.Spec.Changes.ReviewFrequencyChanged = 0
_, err = FromReviewProto(review)
require.NoError(t, err)
// ReviewFrequencyDayOfMonth is nil
review = ToReviewProto(newAccessListReview(t, "access-list-review"))
review.Spec.Changes.ReviewDayOfMonthChanged = 0
_, err = FromReviewProto(review)
require.NoError(t, err)
}
func TestReviewToProtoChanges(t *testing.T) {
@@ -117,43 +128,62 @@ func TestReviewToProtoChanges(t *testing.T) {
// No changes.
review := newAccessListReview(t, "access-list-review")
review.Spec.Changes.FrequencyChanged = 0
review.Spec.Changes.MembershipRequirementsChanged = nil
review.Spec.Changes.RemovedMembers = nil
review.Spec.Changes.ReviewFrequencyChanged = 0
review.Spec.Changes.ReviewDayOfMonthChanged = 0
msg := ToReviewProto(review)
require.Nil(t, msg.Spec.Changes)
// Only frequency changes.
review = newAccessListReview(t, "access-list-review")
review.Spec.Changes.MembershipRequirementsChanged = nil
review.Spec.Changes.RemovedMembers = nil
msg = ToReviewProto(review)
require.Equal(t, review.Spec.Changes.FrequencyChanged, msg.Spec.Changes.FrequencyChanged.AsDuration())
require.Nil(t, msg.Spec.Changes.MembershipRequirementsChanged)
require.Nil(t, msg.Spec.Changes.RemovedMembers)
// Only membership requires changes.
review = newAccessListReview(t, "access-list-review")
review.Spec.Changes.FrequencyChanged = 0
review.Spec.Changes.RemovedMembers = nil
review.Spec.Changes.ReviewFrequencyChanged = 0
review.Spec.Changes.ReviewDayOfMonthChanged = 0
msg = ToReviewProto(review)
require.Equal(t, time.Duration(0), review.Spec.Changes.FrequencyChanged)
require.Equal(t, review.Spec.Changes.MembershipRequirementsChanged.Roles, msg.Spec.Changes.MembershipRequirementsChanged.Roles)
require.Equal(t, review.Spec.Changes.MembershipRequirementsChanged.Traits, traitv1.FromProto(msg.Spec.Changes.MembershipRequirementsChanged.Traits))
require.Nil(t, msg.Spec.Changes.RemovedMembers)
require.Zero(t, msg.Spec.Changes.ReviewFrequencyChanged)
require.Zero(t, msg.Spec.Changes.ReviewDayOfMonthChanged)
// Only removed members changes.
review = newAccessListReview(t, "access-list-review")
review.Spec.Changes.FrequencyChanged = 0
review.Spec.Changes.MembershipRequirementsChanged = nil
review.Spec.Changes.ReviewFrequencyChanged = 0
review.Spec.Changes.ReviewDayOfMonthChanged = 0
msg = ToReviewProto(review)
require.Equal(t, time.Duration(0), review.Spec.Changes.FrequencyChanged)
require.Nil(t, msg.Spec.Changes.MembershipRequirementsChanged)
require.Equal(t, review.Spec.Changes.RemovedMembers, msg.Spec.Changes.RemovedMembers)
require.Zero(t, msg.Spec.Changes.ReviewFrequencyChanged)
require.Zero(t, msg.Spec.Changes.ReviewDayOfMonthChanged)
// Only review frequency changes.
review = newAccessListReview(t, "access-list-review")
review.Spec.Changes.MembershipRequirementsChanged = nil
review.Spec.Changes.RemovedMembers = nil
review.Spec.Changes.ReviewDayOfMonthChanged = 0
msg = ToReviewProto(review)
require.Nil(t, msg.Spec.Changes.MembershipRequirementsChanged)
require.Equal(t, review.Spec.Changes.RemovedMembers, msg.Spec.Changes.RemovedMembers)
require.Equal(t, accesslistv1.ReviewFrequency_REVIEW_FREQUENCY_THREE_MONTHS, msg.Spec.Changes.ReviewFrequencyChanged)
require.Zero(t, msg.Spec.Changes.ReviewDayOfMonthChanged)
// Only review day of month changes.
review = newAccessListReview(t, "access-list-review")
review.Spec.Changes.MembershipRequirementsChanged = nil
review.Spec.Changes.RemovedMembers = nil
review.Spec.Changes.ReviewFrequencyChanged = 0
msg = ToReviewProto(review)
require.Nil(t, msg.Spec.Changes.MembershipRequirementsChanged)
require.Equal(t, review.Spec.Changes.RemovedMembers, msg.Spec.Changes.RemovedMembers)
require.Zero(t, msg.Spec.Changes.ReviewFrequencyChanged)
require.Equal(t, accesslistv1.ReviewDayOfMonth_REVIEW_DAY_OF_MONTH_FIFTEENTH, msg.Spec.Changes.ReviewDayOfMonthChanged)
}
func newAccessListReview(t *testing.T, name string) *accesslist.Review {
@@ -172,7 +202,6 @@ func newAccessListReview(t *testing.T, name string) *accesslist.Review {
ReviewDate: time.Date(2023, 01, 01, 0, 0, 0, 0, time.UTC),
Notes: "some notes",
Changes: accesslist.ReviewChanges{
FrequencyChanged: 20 * time.Hour,
MembershipRequirementsChanged: &accesslist.Requires{
Roles: []string{"role1", "role2"},
Traits: trait.Traits{
@@ -185,6 +214,8 @@ func newAccessListReview(t *testing.T, name string) *accesslist.Review {
"removed2",
"removed3",
},
ReviewFrequencyChanged: accesslist.ThreeMonths,
ReviewDayOfMonthChanged: accesslist.FifteenthDayOfMonth,
},
},
)
+15 -13
View File
@@ -57,14 +57,17 @@ type ReviewSpec struct {
// ReviewChanges are the changes that were made as part of the review.
type ReviewChanges struct {
// FrequencyChanged is populated if the audit frequency was changed.
FrequencyChanged time.Duration `json:"frequency_changed" yaml:"frequency_changed"`
// MembershipRequirementsChanged is populated if the requirements were changed as part of this review.
MembershipRequirementsChanged *Requires `json:"membership_requirements_changed" yaml:"membership_requirements_changed"`
// RemovedMembers contains the members that were removed as part of this review.
RemovedMembers []string `json:"removed_members" yaml:"removed_members"`
// ReviewFrequencyChanged is populated if the review frequency has changed.
ReviewFrequencyChanged ReviewFrequency `json:"review_frequency_changed" yaml:"review_frequency_changed"`
// ReviewDayOfMonthChanged changed is populated if the review day of month has changed.
ReviewDayOfMonthChanged ReviewDayOfMonth `json:"review_day_of_month_changed" yaml:"review_day_of_month_changed"`
}
// NewReview will create a new access list review.
@@ -145,7 +148,8 @@ func (r ReviewSpec) MarshalJSON() ([]byte, error) {
func (r *ReviewChanges) UnmarshalJSON(data []byte) error {
type Alias ReviewChanges
review := struct {
FrequencyChanged string `json:"frequency_changed"`
ReviewFrequencyChanged string `json:"review_frequency_changed"`
ReviewDayOfMonthChanged string `json:"review_day_of_month_changed"`
*Alias
}{
Alias: (*Alias)(r),
@@ -153,22 +157,20 @@ func (r *ReviewChanges) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &review); err != nil {
return trace.Wrap(err)
}
var err error
r.FrequencyChanged, err = time.ParseDuration(review.FrequencyChanged)
if err != nil {
return trace.Wrap(err)
}
r.ReviewFrequencyChanged = parseReviewFrequency(review.ReviewFrequencyChanged)
r.ReviewDayOfMonthChanged = parseReviewDayOfMonth(review.ReviewDayOfMonthChanged)
return nil
}
func (r ReviewChanges) MarshalJSON() ([]byte, error) {
type Alias ReviewChanges
return json.Marshal(&struct {
FrequencyChanged string `json:"frequency_changed"`
ReviewFrequencyChanged string `json:"review_frequency_changed"`
ReviewDayOfMonthChanged string `json:"review_day_of_month_changed"`
Alias
}{
Alias: (Alias)(r),
FrequencyChanged: r.FrequencyChanged.String(),
Alias: (Alias)(r),
ReviewFrequencyChanged: r.ReviewFrequencyChanged.String(),
ReviewDayOfMonthChanged: r.ReviewDayOfMonthChanged.String(),
})
}
+10 -6
View File
@@ -36,7 +36,6 @@ func TestReviewSpecMarshaling(t *testing.T) {
ReviewDate: time.Date(2023, 01, 01, 0, 0, 0, 0, time.UTC),
Notes: "Some notes",
Changes: ReviewChanges{
FrequencyChanged: 300 * time.Second,
MembershipRequirementsChanged: &Requires{
Roles: []string{
"member1",
@@ -57,6 +56,8 @@ func TestReviewSpecMarshaling(t *testing.T) {
"member1",
"member2",
},
ReviewFrequencyChanged: SixMonths,
ReviewDayOfMonthChanged: FirstDayOfMonth,
},
}
@@ -64,15 +65,16 @@ func TestReviewSpecMarshaling(t *testing.T) {
require.NoError(t, err)
require.Equal(t, `{"review_date":"2023-01-01T00:00:00Z","access_list":"access-list","reviewers":["user1","user2"],`+
`"notes":"Some notes","changes":{"frequency_changed":"5m0s","membership_requirements_changed":`+
`{"roles":["member1","member2"],"traits":{"trait1":["value1","value2"],"trait2":["value1","value2"]}},`+
`"notes":"Some notes","changes":{"review_frequency_changed":"6 months","review_day_of_month_changed":"1",`+
`"membership_requirements_changed":{"roles":["member1","member2"],"traits":{"trait1":["value1","value2"],"trait2":["value1","value2"]}},`+
`"removed_members":["member1","member2"]}}`, string(data))
raw := map[string]interface{}{}
require.NoError(t, json.Unmarshal(data, &raw))
require.Equal(t, "2023-01-01T00:00:00Z", raw["review_date"])
require.Equal(t, "5m0s", raw["changes"].(map[string]interface{})["frequency_changed"])
require.Equal(t, SixMonths.String(), raw["changes"].(map[string]interface{})["review_frequency_changed"])
require.Equal(t, FirstDayOfMonth.String(), raw["changes"].(map[string]interface{})["review_day_of_month_changed"])
}
func TestReviewSpecUnmarshaling(t *testing.T) {
@@ -85,7 +87,6 @@ func TestReviewSpecUnmarshaling(t *testing.T) {
"review_date": "2023-01-01T00:00:00Z",
"notes": "Some notes",
"changes": map[string]interface{}{
"frequency_changed": "5m0s",
"membership_requirements_changed": map[string]interface{}{
"roles": []string{
"member1",
@@ -106,6 +107,8 @@ func TestReviewSpecUnmarshaling(t *testing.T) {
"member1",
"member2",
},
"review_frequency_changed": "1 month",
"review_day_of_month_changed": "1",
},
}
@@ -116,5 +119,6 @@ func TestReviewSpecUnmarshaling(t *testing.T) {
require.NoError(t, json.Unmarshal(data, &reviewSpec))
require.Equal(t, time.Date(2023, 01, 01, 0, 0, 0, 0, time.UTC), reviewSpec.ReviewDate)
require.Equal(t, 300*time.Second, reviewSpec.Changes.FrequencyChanged)
require.Equal(t, OneMonth, reviewSpec.Changes.ReviewFrequencyChanged)
require.Equal(t, FirstDayOfMonth, reviewSpec.Changes.ReviewDayOfMonthChanged)
}
@@ -365,7 +365,6 @@ func newAccessList(t *testing.T, clock clockwork.Clock, name string, roles []str
}, accesslist.Spec{
Title: "title",
Audit: accesslist.Audit{
Frequency: time.Hour * 8760, // Roughly a year
NextAuditDate: clock.Now().Add(time.Hour * 48),
},
Owners: []accesslist.Owner{
+9 -5
View File
@@ -2094,7 +2094,7 @@ func TestAccessLists(t *testing.T) {
testResources(t, p, testFuncs[*accesslist.AccessList]{
newResource: func(name string) (*accesslist.AccessList, error) {
return newAccessList(t, name), nil
return newAccessList(t, name, p.backend.Clock()), nil
},
create: func(ctx context.Context, accessList *accesslist.AccessList) error {
_, err := p.accessLists.UpsertAccessList(ctx, accessList)
@@ -2148,7 +2148,9 @@ func TestAccessListMembers(t *testing.T) {
const accessListName = "test-access-list"
p.accessLists.UpsertAccessList(context.Background(), newAccessList(t, accessListName))
clock := clockwork.NewFakeClock()
p.accessLists.UpsertAccessList(context.Background(), newAccessList(t, accessListName, clock))
testResources(t, p, testFuncs[*accesslist.AccessListMember]{
newResource: func(name string) (*accesslist.AccessListMember, error) {
@@ -2575,6 +2577,8 @@ func newProxyEvents(events types.Events, ignoreKinds []types.WatchKind) *proxyEv
func TestCacheWatchKindExistsInEvents(t *testing.T) {
t.Parallel()
clock := clockwork.NewFakeClock()
cases := map[string]Config{
"ForAuth": ForAuth(Config{}),
"ForProxy": ForProxy(Config{}),
@@ -2630,7 +2634,7 @@ func TestCacheWatchKindExistsInEvents(t *testing.T) {
types.KindOktaAssignment: &types.OktaAssignmentV1{},
types.KindIntegration: &types.IntegrationV1{},
types.KindHeadlessAuthentication: &types.HeadlessAuthentication{},
types.KindAccessList: newAccessList(t, "access-list"),
types.KindAccessList: newAccessList(t, "access-list", clock),
types.KindUserLoginState: newUserLoginState(t, "user-login-state"),
types.KindAccessListMember: newAccessListMember(t, "access-list", "member"),
}
@@ -2833,7 +2837,7 @@ func TestInvalidDatabases(t *testing.T) {
}
}
func newAccessList(t *testing.T, name string) *accesslist.AccessList {
func newAccessList(t *testing.T, name string, clock clockwork.Clock) *accesslist.AccessList {
t.Helper()
accessList, err := accesslist.NewAccessList(
@@ -2854,7 +2858,7 @@ func newAccessList(t *testing.T, name string) *accesslist.AccessList {
},
},
Audit: accesslist.Audit{
Frequency: time.Hour,
NextAuditDate: clock.Now(),
},
MembershipRequires: accesslist.Requires{
Roles: []string{"mrole1", "mrole2"},
+20
View File
@@ -18,6 +18,7 @@ package services
import (
"context"
"time"
"github.com/gravitational/trace"
"github.com/jonboulle/clockwork"
@@ -277,3 +278,22 @@ func UserMeetsRequirements(identity tlsca.Identity, requires accesslist.Requires
// The user meets all requirements.
return true
}
// SelectNextReviewDate will select the next review date for the access list.
func SelectNextReviewDate(accessList *accesslist.AccessList) time.Time {
numMonths := int(accessList.Spec.Audit.Recurrence.Frequency)
dayOfMonth := int(accessList.Spec.Audit.Recurrence.DayOfMonth)
// If the last day of the month has been specified, use the 0 day of the
// next month, which will result in the last day of the target month.
if dayOfMonth == int(accesslist.LastDayOfMonth) {
numMonths += 1
dayOfMonth = 0
}
currentReviewDate := accessList.Spec.Audit.NextAuditDate
nextDate := time.Date(currentReviewDate.Year(), currentReviewDate.Month()+time.Month(numMonths), dayOfMonth,
0, 0, 0, 0, time.UTC)
return nextDate
}
+55 -3
View File
@@ -59,7 +59,6 @@ func TestAccessListUnmarshal(t *testing.T) {
},
},
Audit: accesslist.Audit{
Frequency: time.Hour,
NextAuditDate: time.Date(2023, 02, 02, 0, 0, 0, 0, time.UTC),
},
MembershipRequires: accesslist.Requires{
@@ -113,7 +112,6 @@ func TestAccessListMarshal(t *testing.T) {
},
},
Audit: accesslist.Audit{
Frequency: time.Hour,
NextAuditDate: time.Date(2023, 02, 02, 0, 0, 0, 0, time.UTC),
},
MembershipRequires: accesslist.Requires{
@@ -415,6 +413,61 @@ func TestIsAccessListMember(t *testing.T) {
}
}
func TestSelectNextReviewDate(t *testing.T) {
t.Parallel()
tests := []struct {
name string
frequency accesslist.ReviewFrequency
dayOfMonth accesslist.ReviewDayOfMonth
currentReviewDate time.Time
expected time.Time
}{
{
name: "one month, first day",
frequency: accesslist.OneMonth,
dayOfMonth: accesslist.FirstDayOfMonth,
currentReviewDate: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
expected: time.Date(2023, 2, 1, 0, 0, 0, 0, time.UTC),
},
{
name: "one month, fifteenth day",
frequency: accesslist.OneMonth,
dayOfMonth: accesslist.FifteenthDayOfMonth,
currentReviewDate: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
expected: time.Date(2023, 2, 15, 0, 0, 0, 0, time.UTC),
},
{
name: "one month, last day",
frequency: accesslist.OneMonth,
dayOfMonth: accesslist.LastDayOfMonth,
currentReviewDate: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
expected: time.Date(2023, 2, 28, 0, 0, 0, 0, time.UTC),
},
{
name: "six months, last day",
frequency: accesslist.SixMonths,
dayOfMonth: accesslist.LastDayOfMonth,
currentReviewDate: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC),
expected: time.Date(2023, 7, 31, 0, 0, 0, 0, time.UTC),
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
accessList := newAccessList(t)
accessList.Spec.Audit.NextAuditDate = test.currentReviewDate
accessList.Spec.Audit.Recurrence = accesslist.Recurrence{
Frequency: test.frequency,
DayOfMonth: test.dayOfMonth,
}
require.Equal(t, test.expected, SelectNextReviewDate(accessList))
})
}
}
func newAccessList(t *testing.T) *accesslist.AccessList {
t.Helper()
@@ -436,7 +489,6 @@ func newAccessList(t *testing.T) *accesslist.AccessList {
},
},
Audit: accesslist.Audit{
Frequency: time.Hour,
NextAuditDate: time.Date(2024, 6, 1, 0, 0, 0, 0, time.UTC),
},
MembershipRequires: accesslist.Requires{
+9 -9
View File
@@ -48,8 +48,8 @@ func TestAccessListCRUD(t *testing.T) {
require.NoError(t, err)
// Create a couple access lists.
accessList1 := newAccessList(t, "accessList1")
accessList2 := newAccessList(t, "accessList2")
accessList1 := newAccessList(t, "accessList1", clock)
accessList2 := newAccessList(t, "accessList2", clock)
// Initially we expect no access lists.
out, err := service.GetAccessLists(ctx)
@@ -126,7 +126,7 @@ func TestAccessListCRUD(t *testing.T) {
require.Empty(t, out)
// Try to create an access list with duplicate owners.
accessListDuplicateOwners := newAccessList(t, "accessListDuplicateOwners")
accessListDuplicateOwners := newAccessList(t, "accessListDuplicateOwners", clock)
accessListDuplicateOwners.Spec.Owners = append(accessListDuplicateOwners.Spec.Owners, accessListDuplicateOwners.Spec.Owners[0])
_, err = service.UpsertAccessList(ctx, accessListDuplicateOwners)
@@ -147,7 +147,7 @@ func TestAccessListDedupeOwnersBackwardsCompat(t *testing.T) {
require.NoError(t, err)
// Put an unduplicated owners access list in the backend.
accessListDuplicateOwners := newAccessList(t, "accessListDuplicateOwners")
accessListDuplicateOwners := newAccessList(t, "accessListDuplicateOwners", clock)
accessListDuplicateOwners.Spec.Owners = append(accessListDuplicateOwners.Spec.Owners, accessListDuplicateOwners.Spec.Owners[0])
require.Len(t, accessListDuplicateOwners.Spec.Owners, 3)
@@ -176,7 +176,7 @@ func TestAccessListUpsertWithMembers(t *testing.T) {
require.NoError(t, err)
// Create a couple access lists.
accessList1 := newAccessList(t, "accessList1")
accessList1 := newAccessList(t, "accessList1", clock)
cmpOpts := []cmp.Option{
cmpopts.IgnoreFields(header.Metadata{}, "ID", "Revision"),
@@ -252,8 +252,8 @@ func TestAccessListMembersCRUD(t *testing.T) {
require.NoError(t, err)
// Create a couple access lists.
accessList1 := newAccessList(t, "accessList1")
accessList2 := newAccessList(t, "accessList2")
accessList1 := newAccessList(t, "accessList1", clock)
accessList2 := newAccessList(t, "accessList2", clock)
cmpOpts := []cmp.Option{
cmpopts.IgnoreFields(header.Metadata{}, "ID", "Revision"),
@@ -403,7 +403,7 @@ func TestAccessListMembersCRUD(t *testing.T) {
require.ErrorIs(t, err, trace.NotFound("access_list %q doesn't exist", accessList2.GetName()))
}
func newAccessList(t *testing.T, name string) *accesslist.AccessList {
func newAccessList(t *testing.T, name string, clock clockwork.Clock) *accesslist.AccessList {
t.Helper()
accessList, err := accesslist.NewAccessList(
@@ -424,7 +424,7 @@ func newAccessList(t *testing.T, name string) *accesslist.AccessList {
},
},
Audit: accesslist.Audit{
Frequency: time.Hour,
NextAuditDate: clock.Now(),
},
MembershipRequires: accesslist.Requires{
Roles: []string{"mrole1", "mrole2"},
+1 -1
View File
@@ -158,7 +158,7 @@ func TestUnifiedResourceWatcher(t *testing.T) {
},
},
Audit: accesslist.Audit{
Frequency: time.Hour,
NextAuditDate: time.Now(),
},
MembershipRequires: accesslist.Requires{
Roles: []string{"mrole1", "mrole2"},
+3 -2
View File
@@ -232,7 +232,7 @@ func displayAccessLists(format string, accessLists ...*accesslist.AccessList) er
}
func displayAccessListsText(accessLists ...*accesslist.AccessList) error {
table := asciitable.MakeTable([]string{"ID", "Audit Frequency", "Granted Roles", "Granted Traits"})
table := asciitable.MakeTable([]string{"ID", "Review Frequency", "Review Day Of Month", "Granted Roles", "Granted Traits"})
for _, accessList := range accessLists {
grantedRoles := strings.Join(accessList.GetGrants().Roles, ",")
traitStrings := make([]string, 0, len(accessList.GetGrants().Traits))
@@ -242,7 +242,8 @@ func displayAccessListsText(accessLists ...*accesslist.AccessList) error {
grantedTraits := strings.Join(traitStrings, ",")
table.AddRow([]string{
accessList.GetName(),
accessList.GetAuditFrequency().String(),
accessList.Spec.Audit.Recurrence.Frequency.String(),
accessList.Spec.Audit.Recurrence.DayOfMonth.String(),
grantedRoles,
grantedTraits,
})