From 60bcf7dfc35ec498175b2913185032cb015eb1a4 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Tue, 9 Jun 2026 11:38:02 +0200 Subject: [PATCH 01/30] added an implementation of aggregating memory store Signed-off-by: Dmitri --- client/internal/netflow/store/memory.go | 58 +++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index a44505e96f9..f9151726ef1 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -1,7 +1,11 @@ package store import ( + "maps" + "net/netip" + "slices" "sync" + "time" "github.com/google/uuid" @@ -19,6 +23,10 @@ type Memory struct { events map[uuid.UUID]*types.Event } +type AggregatingMemory struct { + Memory +} + func (m *Memory) StoreEvent(event *types.Event) { m.mux.Lock() defer m.mux.Unlock() @@ -48,3 +56,53 @@ func (m *Memory) DeleteEvents(ids []uuid.UUID) { delete(m.events, id) } } + +func (am *AggregatingMemory) StartAggregationWindow() *AggregatingMemory { + am.mux.Lock() + defer am.mux.Unlock() + + toret := AggregatingMemory{Memory: Memory{events: am.Memory.events}} + am.events = make(map[uuid.UUID]*types.Event) + + return &toret +} + +type aggregationKey struct { + destAddr netip.Addr + destPort uint16 + protocol uint8 + icmpType uint8 + ts int64 // used to prevent aggregation on non icmp/udp/tcp events +} + +func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { + aggregated := make(map[aggregationKey]*types.Event) + for _, v := range am.events { + lookupKey := aggregationKey{destAddr: v.DestIP, destPort: v.DestPort, protocol: uint8(v.Protocol), icmpType: v.ICMPCode} + if aggregatedEvent, ok := aggregated[lookupKey]; ok { + switch aggregatedEvent.Protocol { + case types.ICMP, types.ICMPv6, types.UDP, types.TCP: + aggregatedEvent.RxBytes += v.RxBytes + aggregatedEvent.RxPackets += v.RxPackets + aggregatedEvent.TxBytes += v.TxBytes + aggregatedEvent.TxPackets += v.TxPackets + if aggregatedEvent.Timestamp.Compare(v.Timestamp) < 0 { + aggregatedEvent.Timestamp = v.Timestamp + } + // do we aggregate icmp by code? + default: + // shouldn't get here + } + } else { + switch v.Protocol { + case types.ICMP, types.ICMPv6, types.TCP, types.UDP: + aggregated[lookupKey] = v + default: + lookupKey.ts = time.Now().UnixNano() + aggregated[lookupKey] = v + } + } + } + + return slices.Collect(maps.Values(aggregated)) // could return an iterator instead here +} From 243e93477f7c6481e175a06553d006264d7d0270 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Tue, 9 Jun 2026 15:54:39 +0200 Subject: [PATCH 02/30] initial support for aggregation of events Signed-off-by: Dmitri --- client/internal/netflow/logger/logger.go | 8 ++- client/internal/netflow/manager.go | 73 ++++++++++++++++++------ client/internal/netflow/store/memory.go | 11 +++- client/internal/netflow/types/types.go | 15 +++-- 4 files changed, 82 insertions(+), 25 deletions(-) diff --git a/client/internal/netflow/logger/logger.go b/client/internal/netflow/logger/logger.go index 8f8e6878404..deb38bc4db8 100644 --- a/client/internal/netflow/logger/logger.go +++ b/client/internal/netflow/logger/logger.go @@ -27,7 +27,7 @@ type Logger struct { wgIfaceNetV6 netip.Prefix dnsCollection atomic.Bool exitNodeCollection atomic.Bool - Store types.Store + Store types.AggregatingStore } func New(statusRecorder *peer.Status, wgIfaceIPNet, wgIfaceIPNetV6 netip.Prefix) *Logger { @@ -35,7 +35,7 @@ func New(statusRecorder *peer.Status, wgIfaceIPNet, wgIfaceIPNetV6 netip.Prefix) statusRecorder: statusRecorder, wgIfaceNet: wgIfaceIPNet, wgIfaceNetV6: wgIfaceIPNetV6, - Store: store.NewMemoryStore(), + Store: store.NewAggregatingMemoryStore(), } } @@ -125,6 +125,10 @@ func (l *Logger) stop() { l.mux.Unlock() } +func (l *Logger) ResetAggregationWindow() types.FlowEventAggregator { + return l.Store.ResetAggregationWindow() +} + func (l *Logger) GetEvents() []*types.Event { return l.Store.GetEvents() } diff --git a/client/internal/netflow/manager.go b/client/internal/netflow/manager.go index eff083dbfd4..f6397952d63 100644 --- a/client/internal/netflow/manager.go +++ b/client/internal/netflow/manager.go @@ -9,12 +9,14 @@ import ( "sync" "time" + "github.com/cenkalti/backoff/v4" "github.com/google/uuid" log "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/timestamppb" "github.com/netbirdio/netbird/client/internal/netflow/conntrack" "github.com/netbirdio/netbird/client/internal/netflow/logger" + "github.com/netbirdio/netbird/client/internal/netflow/store" nftypes "github.com/netbirdio/netbird/client/internal/netflow/types" "github.com/netbirdio/netbird/client/internal/peer" "github.com/netbirdio/netbird/flow/client" @@ -23,14 +25,15 @@ import ( // Manager handles netflow tracking and logging type Manager struct { - mux sync.Mutex - shutdownWg sync.WaitGroup - logger nftypes.FlowLogger - flowConfig *nftypes.FlowConfig - conntrack nftypes.ConnTracker - receiverClient *client.GRPCClient - publicKey []byte - cancel context.CancelFunc + mux sync.Mutex + shutdownWg sync.WaitGroup + logger nftypes.FlowLogger + flowConfig *nftypes.FlowConfig + conntrack nftypes.ConnTracker + receiverClient *client.GRPCClient + eventsWithoutAcks nftypes.Store + publicKey []byte + cancel context.CancelFunc } // NewManager creates a new netflow manager @@ -48,9 +51,10 @@ func NewManager(iface nftypes.IFaceMapper, publicKey []byte, statusRecorder *pee } return &Manager{ - logger: flowLogger, - conntrack: ct, - publicKey: publicKey, + logger: flowLogger, + conntrack: ct, + publicKey: publicKey, + eventsWithoutAcks: store.NewMemoryStore(), } } @@ -107,7 +111,7 @@ func (m *Manager) resetClient() error { ctx, cancel := context.WithCancel(context.Background()) m.cancel = cancel - m.shutdownWg.Add(2) + m.shutdownWg.Add(3) go func() { defer m.shutdownWg.Done() m.receiveACKs(ctx, flowClient) @@ -116,6 +120,10 @@ func (m *Manager) resetClient() error { defer m.shutdownWg.Done() m.startSender(ctx) }() + go func() { + defer m.shutdownWg.Done() + m.startRetries(ctx) + }() return nil } @@ -207,13 +215,16 @@ func (m *Manager) startSender(ctx context.Context) { case <-ctx.Done(): return case <-ticker.C: - events := m.logger.GetEvents() + collectedEvents := m.logger.ResetAggregationWindow() + events := collectedEvents.GetAggregatedEvents() for _, event := range events { + // handle retries, grace period? if err := m.send(event); err != nil { log.Errorf("failed to send flow event to server: %v", err) - continue + } else { + log.Tracef("sent flow event: %s", event.ID) } - log.Tracef("sent flow event: %s", event.ID) + m.eventsWithoutAcks.StoreEvent(event) } } } @@ -227,7 +238,7 @@ func (m *Manager) receiveACKs(ctx context.Context, client *client.GRPCClient) { return nil } log.Tracef("received flow event ack: %s", id) - m.logger.DeleteEvents([]uuid.UUID{id}) + m.eventsWithoutAcks.DeleteEvents([]uuid.UUID{id}) return nil }) @@ -236,6 +247,36 @@ func (m *Manager) receiveACKs(ctx context.Context, client *client.GRPCClient) { } } +func (m *Manager) startRetries(ctx context.Context) { + ticker := time.NewTimer(time.Second) + retryBackoff := backoff.WithContext(&backoff.ExponentialBackOff{ + InitialInterval: 1 * time.Second, + RandomizationFactor: 0.5, + Multiplier: 1.7, + MaxInterval: m.flowConfig.Interval / 2, + MaxElapsedTime: 3 * 30 * 24 * time.Hour, // 3 months + Stop: backoff.Stop, + Clock: backoff.SystemClock, + }, ctx) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + for _, e := range m.eventsWithoutAcks.GetEvents() { + if err := m.send(e); err != nil { + ticker = time.NewTimer(retryBackoff.NextBackOff()) + break + } + } + retryBackoff.Reset() + ticker = time.NewTimer(time.Second) + } + } +} + func (m *Manager) send(event *nftypes.Event) error { m.mux.Lock() client := m.receiverClient diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index f9151726ef1..92e4578fc25 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -57,11 +57,15 @@ func (m *Memory) DeleteEvents(ids []uuid.UUID) { } } -func (am *AggregatingMemory) StartAggregationWindow() *AggregatingMemory { +func NewAggregatingMemoryStore() *AggregatingMemory { + return &AggregatingMemory{Memory{events: make(map[uuid.UUID]*types.Event)}} +} + +func (am *AggregatingMemory) ResetAggregationWindow() types.FlowEventAggregator { am.mux.Lock() defer am.mux.Unlock() - toret := AggregatingMemory{Memory: Memory{events: am.Memory.events}} + toret := AggregatingMemory{Memory: Memory{events: am.events}} am.events = make(map[uuid.UUID]*types.Event) return &toret @@ -82,6 +86,7 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { if aggregatedEvent, ok := aggregated[lookupKey]; ok { switch aggregatedEvent.Protocol { case types.ICMP, types.ICMPv6, types.UDP, types.TCP: + // track the number of connections, duration?, open and close events? aggregatedEvent.RxBytes += v.RxBytes aggregatedEvent.RxPackets += v.RxPackets aggregatedEvent.TxBytes += v.TxBytes @@ -98,7 +103,7 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { case types.ICMP, types.ICMPv6, types.TCP, types.UDP: aggregated[lookupKey] = v default: - lookupKey.ts = time.Now().UnixNano() + lookupKey.ts = time.Now().UnixNano() // to make the lookup key unique so we don't aggregate on it aggregated[lookupKey] = v } } diff --git a/client/internal/netflow/types/types.go b/client/internal/netflow/types/types.go index 3f7d0d0add2..55c7494be02 100644 --- a/client/internal/netflow/types/types.go +++ b/client/internal/netflow/types/types.go @@ -114,13 +114,15 @@ type FlowManager interface { GetLogger() FlowLogger } +type FlowEventAggregator interface { + ResetAggregationWindow() FlowEventAggregator + GetAggregatedEvents() []*Event +} + type FlowLogger interface { + ResetAggregationWindow() FlowEventAggregator // StoreEvent stores a flow event StoreEvent(flowEvent EventFields) - // GetEvents returns all stored events - GetEvents() []*Event - // DeleteEvents deletes events from the store - DeleteEvents([]uuid.UUID) // Close closes the logger Close() // Enable enables the flow logger receiver @@ -140,6 +142,11 @@ type Store interface { Close() } +type AggregatingStore interface { + FlowEventAggregator + Store +} + // ConnTracker defines the interface for connection tracking functionality type ConnTracker interface { // Start begins tracking connections by listening for conntrack events. From b654a75a4323182490395cfbef6851d82ab98559 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Wed, 10 Jun 2026 10:33:37 +0200 Subject: [PATCH 03/30] added tcp-aggregation test Signed-off-by: Dmitri --- client/internal/netflow/manager.go | 2 +- client/internal/netflow/store/memory.go | 4 +- .../netflow/store/tcp_aggregation_test.go | 272 ++++++++++++++++++ 3 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 client/internal/netflow/store/tcp_aggregation_test.go diff --git a/client/internal/netflow/manager.go b/client/internal/netflow/manager.go index f6397952d63..0e65c880eb1 100644 --- a/client/internal/netflow/manager.go +++ b/client/internal/netflow/manager.go @@ -218,7 +218,6 @@ func (m *Manager) startSender(ctx context.Context) { collectedEvents := m.logger.ResetAggregationWindow() events := collectedEvents.GetAggregatedEvents() for _, event := range events { - // handle retries, grace period? if err := m.send(event); err != nil { log.Errorf("failed to send flow event to server: %v", err) } else { @@ -265,6 +264,7 @@ func (m *Manager) startRetries(ctx context.Context) { case <-ctx.Done(): return case <-ticker.C: + // TODO: grace period on retries to avoid early retries? for _, e := range m.eventsWithoutAcks.GetEvents() { if err := m.send(e); err != nil { ticker = time.NewTimer(retryBackoff.NextBackOff()) diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index 92e4578fc25..10da74d8bcb 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -91,8 +91,10 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { aggregatedEvent.RxPackets += v.RxPackets aggregatedEvent.TxBytes += v.TxBytes aggregatedEvent.TxPackets += v.TxPackets - if aggregatedEvent.Timestamp.Compare(v.Timestamp) < 0 { + if aggregatedEvent.Timestamp.Compare(v.Timestamp) > 0 { aggregatedEvent.Timestamp = v.Timestamp + aggregatedEvent.ID = v.ID + aggregatedEvent.Type = v.Type } // do we aggregate icmp by code? default: diff --git a/client/internal/netflow/store/tcp_aggregation_test.go b/client/internal/netflow/store/tcp_aggregation_test.go new file mode 100644 index 00000000000..8b023ce6985 --- /dev/null +++ b/client/internal/netflow/store/tcp_aggregation_test.go @@ -0,0 +1,272 @@ +package store + +import ( + "net/netip" + "testing" + "time" + + "github.com/google/uuid" + "github.com/netbirdio/netbird/client/internal/netflow/types" + "github.com/stretchr/testify/assert" +) + +var pregeneratedUUIDs = func() []uuid.UUID { + toret := make([]uuid.UUID, 0) + for range make([]int, 10) { + toret = append(toret, uuid.New()) + } + return toret +}() + +func TestTcpAggregation(t *testing.T) { + var tests = []struct { + description string + events []*types.Event + expected []*types.Event + }{ + { + description: "start and stop", + events: []*types.Event{ + { + ID: pregeneratedUUIDs[0], + Timestamp: time.Unix(100, 100), + EventFields: types.EventFields{ + FlowID: pregeneratedUUIDs[1], + Type: types.TypeStart, + RuleID: []byte("rule-id-1"), + Direction: types.Egress, + Protocol: types.TCP, + SourceIP: ipAddr("1.1.1.1"), + SourcePort: 1234, + DestIP: ipAddr("2.2.2.2"), + DestPort: 443, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: 10, + TxPackets: 20, + RxBytes: 10000, + TxBytes: 20000, + }}, + { + ID: pregeneratedUUIDs[2], + Timestamp: time.Unix(100, 100).Add(time.Second), + EventFields: types.EventFields{ + FlowID: pregeneratedUUIDs[1], + Type: types.TypeEnd, + RuleID: []byte("rule-id-1"), + Direction: types.Egress, + Protocol: types.TCP, + SourceIP: ipAddr("1.1.1.1"), + SourcePort: 1234, + DestIP: ipAddr("2.2.2.2"), + DestPort: 443, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: 30, + TxPackets: 40, + RxBytes: 30000, + TxBytes: 40000, + }}, + }, + expected: []*types.Event{ + { + ID: pregeneratedUUIDs[0], + Timestamp: time.Unix(100, 100), + EventFields: types.EventFields{ + FlowID: pregeneratedUUIDs[1], + Type: types.TypeStart, + RuleID: []byte("rule-id-1"), + Direction: types.Egress, + Protocol: types.TCP, + SourceIP: ipAddr("1.1.1.1"), + SourcePort: 1234, + DestIP: ipAddr("2.2.2.2"), + DestPort: 443, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: 40, + TxPackets: 60, + RxBytes: 40000, + TxBytes: 60000, + }}, + }, + }, + { + description: "start and drop", + events: []*types.Event{ + { + ID: pregeneratedUUIDs[0], + Timestamp: time.Unix(100, 100), + EventFields: types.EventFields{ + FlowID: pregeneratedUUIDs[1], + Type: types.TypeStart, + RuleID: []byte("rule-id-1"), + Direction: types.Egress, + Protocol: types.TCP, + SourceIP: ipAddr("1.1.1.1"), + SourcePort: 1234, + DestIP: ipAddr("2.2.2.2"), + DestPort: 443, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: 10, + TxPackets: 20, + RxBytes: 10000, + TxBytes: 20000, + }}, + { + ID: pregeneratedUUIDs[2], + Timestamp: time.Unix(100, 100).Add(time.Second), + EventFields: types.EventFields{ + FlowID: pregeneratedUUIDs[1], + Type: types.TypeDrop, + RuleID: []byte("rule-id-1"), + Direction: types.Egress, + Protocol: types.TCP, + SourceIP: ipAddr("1.1.1.1"), + SourcePort: 1234, + DestIP: ipAddr("2.2.2.2"), + DestPort: 443, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: 30, + TxPackets: 40, + RxBytes: 30000, + TxBytes: 40000, + }}, + }, + expected: []*types.Event{ + { + ID: pregeneratedUUIDs[0], + Timestamp: time.Unix(100, 100), + EventFields: types.EventFields{ + FlowID: pregeneratedUUIDs[1], + Type: types.TypeStart, + RuleID: []byte("rule-id-1"), + Direction: types.Egress, + Protocol: types.TCP, + SourceIP: ipAddr("1.1.1.1"), + SourcePort: 1234, + DestIP: ipAddr("2.2.2.2"), + DestPort: 443, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: 40, + TxPackets: 60, + RxBytes: 40000, + TxBytes: 60000, + }}, + }, + }, + { + description: "start only", + events: []*types.Event{ + { + ID: pregeneratedUUIDs[0], + Timestamp: time.Unix(100, 100), + EventFields: types.EventFields{ + FlowID: pregeneratedUUIDs[1], + Type: types.TypeStart, + RuleID: []byte("rule-id-1"), + Direction: types.Egress, + Protocol: types.TCP, + SourceIP: ipAddr("1.1.1.1"), + SourcePort: 1234, + DestIP: ipAddr("2.2.2.2"), + DestPort: 443, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: 10, + TxPackets: 20, + RxBytes: 10000, + TxBytes: 20000, + }}, + }, + expected: []*types.Event{ + { + ID: pregeneratedUUIDs[0], + Timestamp: time.Unix(100, 100), + EventFields: types.EventFields{ + FlowID: pregeneratedUUIDs[1], + Type: types.TypeStart, + RuleID: []byte("rule-id-1"), + Direction: types.Egress, + Protocol: types.TCP, + SourceIP: ipAddr("1.1.1.1"), + SourcePort: 1234, + DestIP: ipAddr("2.2.2.2"), + DestPort: 443, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: 10, + TxPackets: 20, + RxBytes: 10000, + TxBytes: 20000, + }}, + }, + }, + { + description: "drop only", + events: []*types.Event{ + { + ID: pregeneratedUUIDs[2], + Timestamp: time.Unix(100, 100).Add(time.Second), + EventFields: types.EventFields{ + FlowID: pregeneratedUUIDs[1], + Type: types.TypeEnd, + RuleID: []byte("rule-id-1"), + Direction: types.Egress, + Protocol: types.TCP, + SourceIP: ipAddr("1.1.1.1"), + SourcePort: 1234, + DestIP: ipAddr("2.2.2.2"), + DestPort: 443, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: 30, + TxPackets: 40, + RxBytes: 30000, + TxBytes: 40000, + }}, + }, + expected: []*types.Event{ + { + ID: pregeneratedUUIDs[2], + Timestamp: time.Unix(100, 100).Add(time.Second), + EventFields: types.EventFields{ + FlowID: pregeneratedUUIDs[1], + Type: types.TypeEnd, + RuleID: []byte("rule-id-1"), + Direction: types.Egress, + Protocol: types.TCP, + SourceIP: ipAddr("1.1.1.1"), + SourcePort: 1234, + DestIP: ipAddr("2.2.2.2"), + DestPort: 443, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: 30, + TxPackets: 40, + RxBytes: 30000, + TxBytes: 40000, + }}, + }, + }} + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + store := NewAggregatingMemoryStore() + for _, e := range tt.events { + store.StoreEvent(e) + } + events := store.GetAggregatedEvents() + assert.Len(t, events, len(tt.expected)) + assert.ElementsMatch(t, events, tt.expected) + }) + } +} + +func ipAddr(a string) netip.Addr { + addr, _ := netip.ParseAddr(a) + return addr +} From 101ae3ca770b91770c716bfefa294b292ad4b22a Mon Sep 17 00:00:00 2001 From: Dmitri Date: Wed, 10 Jun 2026 14:48:58 +0200 Subject: [PATCH 04/30] added manager integration test Signed-off-by: Dmitri --- client/internal/netflow/manager.go | 4 +- .../netflow/manager_integration_test.go | 291 ++++++++++++++++++ 2 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 client/internal/netflow/manager_integration_test.go diff --git a/client/internal/netflow/manager.go b/client/internal/netflow/manager.go index 0e65c880eb1..d6669f9ac15 100644 --- a/client/internal/netflow/manager.go +++ b/client/internal/netflow/manager.go @@ -34,6 +34,7 @@ type Manager struct { eventsWithoutAcks nftypes.Store publicKey []byte cancel context.CancelFunc + retryInterval time.Duration } // NewManager creates a new netflow manager @@ -54,6 +55,7 @@ func NewManager(iface nftypes.IFaceMapper, publicKey []byte, statusRecorder *pee logger: flowLogger, conntrack: ct, publicKey: publicKey, + retryInterval: time.Second, eventsWithoutAcks: store.NewMemoryStore(), } } @@ -247,7 +249,7 @@ func (m *Manager) receiveACKs(ctx context.Context, client *client.GRPCClient) { } func (m *Manager) startRetries(ctx context.Context) { - ticker := time.NewTimer(time.Second) + ticker := time.NewTimer(m.retryInterval) retryBackoff := backoff.WithContext(&backoff.ExponentialBackOff{ InitialInterval: 1 * time.Second, RandomizationFactor: 0.5, diff --git a/client/internal/netflow/manager_integration_test.go b/client/internal/netflow/manager_integration_test.go new file mode 100644 index 00000000000..9029bdda2fa --- /dev/null +++ b/client/internal/netflow/manager_integration_test.go @@ -0,0 +1,291 @@ +package netflow + +import ( + "context" + "errors" + "fmt" + "net" + "net/netip" + "slices" + "testing" + "time" + + "github.com/google/uuid" + "github.com/netbirdio/netbird/client/iface/wgaddr" + "github.com/netbirdio/netbird/client/internal/netflow/types" + "github.com/netbirdio/netbird/flow/proto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "google.golang.org/grpc" +) + +type testServer struct { + proto.UnimplementedFlowServiceServer + events chan *proto.FlowEvent + acks chan *proto.FlowEventAck + grpcSrv *grpc.Server + addr string + handlerDone chan struct{} // signaled each time Events() exits + handlerStarted chan struct{} // signaled each time Events() begins +} + +func newTestServer(t *testing.T) *testServer { + listener, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + + s := &testServer{ + events: make(chan *proto.FlowEvent, 100), + acks: make(chan *proto.FlowEventAck, 100), + grpcSrv: grpc.NewServer(), + addr: listener.Addr().String(), + handlerDone: make(chan struct{}, 10), + handlerStarted: make(chan struct{}, 10), + } + + proto.RegisterFlowServiceServer(s.grpcSrv, s) + + go func() { + if err := s.grpcSrv.Serve(listener); err != nil && !errors.Is(err, grpc.ErrServerStopped) { + t.Logf("server error: %v", err) + } + }() + + t.Cleanup(func() { + s.grpcSrv.Stop() + }) + + return s +} + +func (s *testServer) Events(stream proto.FlowService_EventsServer) error { + defer func() { + select { + case s.handlerDone <- struct{}{}: + default: + } + }() + + err := stream.Send(&proto.FlowEventAck{IsInitiator: true}) + if err != nil { + return err + } + + select { + case s.handlerStarted <- struct{}{}: + default: + } + + ctx, cancel := context.WithCancel(stream.Context()) + defer cancel() + + go func() { + defer cancel() + for { + event, err := stream.Recv() + if err != nil { + return + } + + if !event.IsInitiator { + select { + case s.events <- event: + case <-ctx.Done(): + return + } + } + } + }() + + for { + select { + case ack := <-s.acks: + if err := stream.Send(ack); err != nil { + return err + } + case <-ctx.Done(): + return ctx.Err() + } + } +} + +func TestSendEventReceiveAck(t *testing.T) { + _, cancel := context.WithTimeout(context.Background(), 10*time.Second) + t.Cleanup(cancel) + + server := newTestServer(t) + manager := createManager(t, server.addr, 60*time.Second) // set high to prevent retries in this test + defer manager.Close() + + assert.Eventually(t, func() bool { + select { + case <-server.handlerStarted: + return true + default: + return false + } + }, 3*time.Second, 100*time.Millisecond) + + event1 := types.EventFields{ + FlowID: uuid.New(), + Type: types.TypeStart, + Direction: types.Ingress, + DestIP: ipAddr("172.16.1.2"), + DestPort: 2345, + Protocol: 6, + } + manager.logger.StoreEvent(event1) + event2 := types.EventFields{ + FlowID: uuid.New(), + Type: types.TypeStart, + Direction: types.Ingress, + DestIP: ipAddr("172.16.1.1"), + DestPort: 1234, + Protocol: 6, + } + manager.logger.StoreEvent(event2) + + // verify the server received logged events + serverSideEvents := make([]*proto.FlowEvent, 0) + assert.Eventually(t, func() bool { + select { + case event := <-server.events: + serverSideEvents = append(serverSideEvents, event) + if len(serverSideEvents) == 2 { + return true + } + default: + if len(serverSideEvents) == 2 { + return true + } + } + return false + }, 5*time.Second, 100*time.Millisecond) + + serverSideFlowIds := make([]uuid.UUID, 0, 2) + slices.Values(serverSideEvents)(func(e *proto.FlowEvent) bool { + id, err := uuid.FromBytes(e.FlowFields.FlowId) + assert.NoError(t, err) + serverSideFlowIds = append(serverSideFlowIds, id) + return true + }) + assert.ElementsMatch(t, []uuid.UUID{event1.FlowID, event2.FlowID}, serverSideFlowIds) + + // verify the manager tracks un-acked events + unackedEvents := manager.eventsWithoutAcks.GetEvents() + assert.Len(t, unackedEvents, 2) + flowIds := make([]uuid.UUID, 0) + slices.Values(unackedEvents)(func(e *types.Event) bool { + flowIds = append(flowIds, e.FlowID) + return true + }) + assert.ElementsMatch(t, flowIds, []uuid.UUID{event1.FlowID, event2.FlowID}) +} + +// verify handling of retries: +// - unacked events are retried +// - when acks arrive, events are removed from the un-acked event tracker +func TestRetryEvents(t *testing.T) { + _, cancel := context.WithTimeout(context.Background(), 10*time.Second) + t.Cleanup(cancel) + + server := newTestServer(t) + manager := createManager(t, server.addr, time.Second) // set low to start retries sooner + defer manager.Close() + + assert.Eventually(t, func() bool { + select { + case <-server.handlerStarted: + return true + default: + return false + } + }, 3*time.Second, 100*time.Millisecond) + + event1 := types.EventFields{ + FlowID: uuid.New(), + Type: types.TypeStart, + Direction: types.Ingress, + DestIP: ipAddr("172.16.1.2"), + DestPort: 2345, + Protocol: 6, + } + manager.logger.StoreEvent(event1) + event2 := types.EventFields{ + FlowID: uuid.New(), + Type: types.TypeStart, + Direction: types.Ingress, + DestIP: ipAddr("172.16.1.1"), + DestPort: 1234, + Protocol: 6, + } + manager.logger.StoreEvent(event2) + + // verify the server received retries of logged events + serverSideEvents := make([]*proto.FlowEvent, 0) + func() { + c := time.After(2500 * time.Millisecond) + for { + select { + case event := <-server.events: + serverSideEvents = append(serverSideEvents, event) + case <-c: + return + } + } + }() + assert.True(t, len(serverSideEvents) > 2) // must see retries + + uniqueServerSideEvents := make(map[uuid.UUID]*proto.FlowEvent) + slices.Values(serverSideEvents)(func(e *proto.FlowEvent) bool { + id, err := uuid.FromBytes(e.FlowFields.FlowId) + assert.NoError(t, err) + uniqueServerSideEvents[id] = e + return true + }) + assert.Contains(t, uniqueServerSideEvents, event1.FlowID) + assert.Contains(t, uniqueServerSideEvents, event2.FlowID) + + // ack events + server.acks <- &proto.FlowEventAck{EventId: uniqueServerSideEvents[event1.FlowID].EventId} + server.acks <- &proto.FlowEventAck{EventId: uniqueServerSideEvents[event2.FlowID].EventId} + + assert.EventuallyWithT(t, func(c *assert.CollectT) { + unackedEvents := manager.eventsWithoutAcks.GetEvents() + assert.Empty(c, unackedEvents) + + }, 3*time.Second, 100*time.Millisecond) +} + +func createManager(t *testing.T, serverAddr string, retryInterval time.Duration) *Manager { + t.Helper() + + mockIFace := &mockIFaceMapper{ + address: wgaddr.Address{ + Network: netip.MustParsePrefix("192.168.1.1/32"), + }, + isUserspaceBind: true, + } + + publicKey := []byte("test-public-key") + manager := NewManager(mockIFace, publicKey, nil) + manager.retryInterval = retryInterval + + initialConfig := &types.FlowConfig{ + Enabled: true, + URL: fmt.Sprintf("http://%s", serverAddr), + TokenPayload: "initial-payload", + TokenSignature: "initial-signature", + Interval: 500 * time.Millisecond, + } + + err := manager.Update(initialConfig) + require.NoError(t, err) + + return manager +} + +func ipAddr(a string) netip.Addr { + addr, _ := netip.ParseAddr(a) + return addr +} From 8f99362a25a2a260fea72b022f7cd56b0d1bd28c Mon Sep 17 00:00:00 2001 From: Dmitri Date: Wed, 10 Jun 2026 16:06:29 +0200 Subject: [PATCH 05/30] added tracking of the number of start-, drop, and end-events in an aggregation window Signed-off-by: Dmitri --- client/internal/netflow/store/memory.go | 21 +- .../netflow/store/tcp_aggregation_test.go | 16 +- client/internal/netflow/types/types.go | 12 + flow/proto/flow.pb.go | 362 +++++++----------- flow/proto/flow.proto | 3 + flow/proto/flow_grpc.pb.go | 94 ++--- 6 files changed, 233 insertions(+), 275 deletions(-) diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index 10da74d8bcb..f1a216348b7 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -91,6 +91,14 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { aggregatedEvent.RxPackets += v.RxPackets aggregatedEvent.TxBytes += v.TxBytes aggregatedEvent.TxPackets += v.TxPackets + switch v.Type { + case types.TypeStart: + aggregatedEvent.NumOfStarts += 1 + case types.TypeDrop: + aggregatedEvent.NumOfDrops += 1 + case types.TypeEnd: + aggregatedEvent.NumOfEnds += 1 + } if aggregatedEvent.Timestamp.Compare(v.Timestamp) > 0 { aggregatedEvent.Timestamp = v.Timestamp aggregatedEvent.ID = v.ID @@ -103,10 +111,19 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { } else { switch v.Protocol { case types.ICMP, types.ICMPv6, types.TCP, types.UDP: - aggregated[lookupKey] = v + event := v.Clone() + aggregated[lookupKey] = event + switch event.Type { + case types.TypeStart: + event.NumOfStarts += 1 + case types.TypeDrop: + event.NumOfDrops += 1 + case types.TypeEnd: + event.NumOfEnds += 1 + } default: lookupKey.ts = time.Now().UnixNano() // to make the lookup key unique so we don't aggregate on it - aggregated[lookupKey] = v + aggregated[lookupKey] = v.Clone() } } } diff --git a/client/internal/netflow/store/tcp_aggregation_test.go b/client/internal/netflow/store/tcp_aggregation_test.go index 8b023ce6985..4d28c454fcb 100644 --- a/client/internal/netflow/store/tcp_aggregation_test.go +++ b/client/internal/netflow/store/tcp_aggregation_test.go @@ -88,6 +88,9 @@ func TestTcpAggregation(t *testing.T) { TxPackets: 60, RxBytes: 40000, TxBytes: 60000, + NumOfStarts: 1, + NumOfEnds: 1, + NumOfDrops: 0, }}, }, }, @@ -155,6 +158,9 @@ func TestTcpAggregation(t *testing.T) { TxPackets: 60, RxBytes: 40000, TxBytes: 60000, + NumOfStarts: 1, + NumOfEnds: 0, + NumOfDrops: 1, }}, }, }, @@ -202,6 +208,9 @@ func TestTcpAggregation(t *testing.T) { TxPackets: 20, RxBytes: 10000, TxBytes: 20000, + NumOfStarts: 1, + NumOfEnds: 0, + NumOfDrops: 0, }}, }, }, @@ -213,7 +222,7 @@ func TestTcpAggregation(t *testing.T) { Timestamp: time.Unix(100, 100).Add(time.Second), EventFields: types.EventFields{ FlowID: pregeneratedUUIDs[1], - Type: types.TypeEnd, + Type: types.TypeDrop, RuleID: []byte("rule-id-1"), Direction: types.Egress, Protocol: types.TCP, @@ -235,7 +244,7 @@ func TestTcpAggregation(t *testing.T) { Timestamp: time.Unix(100, 100).Add(time.Second), EventFields: types.EventFields{ FlowID: pregeneratedUUIDs[1], - Type: types.TypeEnd, + Type: types.TypeDrop, RuleID: []byte("rule-id-1"), Direction: types.Egress, Protocol: types.TCP, @@ -249,6 +258,9 @@ func TestTcpAggregation(t *testing.T) { TxPackets: 40, RxBytes: 30000, TxBytes: 40000, + NumOfStarts: 0, + NumOfEnds: 0, + NumOfDrops: 1, }}, }, }} diff --git a/client/internal/netflow/types/types.go b/client/internal/netflow/types/types.go index 55c7494be02..d0952fd2c58 100644 --- a/client/internal/netflow/types/types.go +++ b/client/internal/netflow/types/types.go @@ -2,6 +2,7 @@ package types import ( "net/netip" + "slices" "strconv" "time" @@ -92,6 +93,17 @@ type EventFields struct { TxPackets uint64 RxBytes uint64 TxBytes uint64 + NumOfStarts uint64 + NumOfEnds uint64 + NumOfDrops uint64 +} + +func (e *Event) Clone() *Event { + toret := *e + toret.RuleID = slices.Clone(e.RuleID) + toret.SourceResourceID = slices.Clone(e.SourceResourceID) + toret.DestResourceID = slices.Clone(e.DestResourceID) + return &toret } type FlowConfig struct { diff --git a/flow/proto/flow.pb.go b/flow/proto/flow.pb.go index 04e6e379217..ca4ccc42858 100644 --- a/flow/proto/flow.pb.go +++ b/flow/proto/flow.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 -// protoc v3.21.9 +// protoc-gen-go v1.36.11 +// protoc v7.35.0 // source: flow.proto package proto @@ -12,6 +12,7 @@ import ( timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -125,27 +126,24 @@ func (Direction) EnumDescriptor() ([]byte, []int) { } type FlowEvent struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Unique client event identifier EventId []byte `protobuf:"bytes,1,opt,name=event_id,json=eventId,proto3" json:"event_id,omitempty"` // When the event occurred Timestamp *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Public key of the sending peer - PublicKey []byte `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` - FlowFields *FlowFields `protobuf:"bytes,4,opt,name=flow_fields,json=flowFields,proto3" json:"flow_fields,omitempty"` - IsInitiator bool `protobuf:"varint,5,opt,name=isInitiator,proto3" json:"isInitiator,omitempty"` + PublicKey []byte `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + FlowFields *FlowFields `protobuf:"bytes,4,opt,name=flow_fields,json=flowFields,proto3" json:"flow_fields,omitempty"` + IsInitiator bool `protobuf:"varint,5,opt,name=isInitiator,proto3" json:"isInitiator,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *FlowEvent) Reset() { *x = FlowEvent{} - if protoimpl.UnsafeEnabled { - mi := &file_flow_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_flow_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FlowEvent) String() string { @@ -156,7 +154,7 @@ func (*FlowEvent) ProtoMessage() {} func (x *FlowEvent) ProtoReflect() protoreflect.Message { mi := &file_flow_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -207,22 +205,19 @@ func (x *FlowEvent) GetIsInitiator() bool { } type FlowEventAck struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Unique client event identifier that has been ack'ed - EventId []byte `protobuf:"bytes,1,opt,name=event_id,json=eventId,proto3" json:"event_id,omitempty"` - IsInitiator bool `protobuf:"varint,2,opt,name=isInitiator,proto3" json:"isInitiator,omitempty"` + EventId []byte `protobuf:"bytes,1,opt,name=event_id,json=eventId,proto3" json:"event_id,omitempty"` + IsInitiator bool `protobuf:"varint,2,opt,name=isInitiator,proto3" json:"isInitiator,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *FlowEventAck) Reset() { *x = FlowEventAck{} - if protoimpl.UnsafeEnabled { - mi := &file_flow_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_flow_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FlowEventAck) String() string { @@ -233,7 +228,7 @@ func (*FlowEventAck) ProtoMessage() {} func (x *FlowEventAck) ProtoReflect() protoreflect.Message { mi := &file_flow_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -263,10 +258,7 @@ func (x *FlowEventAck) GetIsInitiator() bool { } type FlowFields struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Unique client flow session identifier FlowId []byte `protobuf:"bytes,1,opt,name=flow_id,json=flowId,proto3" json:"flow_id,omitempty"` // Flow type @@ -283,7 +275,7 @@ type FlowFields struct { DestIp []byte `protobuf:"bytes,7,opt,name=dest_ip,json=destIp,proto3" json:"dest_ip,omitempty"` // Layer 4 -specific information // - // Types that are assignable to ConnectionInfo: + // Types that are valid to be assigned to ConnectionInfo: // // *FlowFields_PortInfo // *FlowFields_IcmpInfo @@ -297,15 +289,18 @@ type FlowFields struct { // Resource ID SourceResourceId []byte `protobuf:"bytes,14,opt,name=source_resource_id,json=sourceResourceId,proto3" json:"source_resource_id,omitempty"` DestResourceId []byte `protobuf:"bytes,15,opt,name=dest_resource_id,json=destResourceId,proto3" json:"dest_resource_id,omitempty"` + NumOfStarts uint64 `protobuf:"varint,16,opt,name=num_of_starts,json=numOfStarts,proto3" json:"num_of_starts,omitempty"` + NumOfEnds uint64 `protobuf:"varint,17,opt,name=num_of_ends,json=numOfEnds,proto3" json:"num_of_ends,omitempty"` + NumOfDrops uint64 `protobuf:"varint,18,opt,name=num_of_drops,json=numOfDrops,proto3" json:"num_of_drops,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *FlowFields) Reset() { *x = FlowFields{} - if protoimpl.UnsafeEnabled { - mi := &file_flow_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_flow_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FlowFields) String() string { @@ -316,7 +311,7 @@ func (*FlowFields) ProtoMessage() {} func (x *FlowFields) ProtoReflect() protoreflect.Message { mi := &file_flow_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -380,23 +375,27 @@ func (x *FlowFields) GetDestIp() []byte { return nil } -func (m *FlowFields) GetConnectionInfo() isFlowFields_ConnectionInfo { - if m != nil { - return m.ConnectionInfo +func (x *FlowFields) GetConnectionInfo() isFlowFields_ConnectionInfo { + if x != nil { + return x.ConnectionInfo } return nil } func (x *FlowFields) GetPortInfo() *PortInfo { - if x, ok := x.GetConnectionInfo().(*FlowFields_PortInfo); ok { - return x.PortInfo + if x != nil { + if x, ok := x.ConnectionInfo.(*FlowFields_PortInfo); ok { + return x.PortInfo + } } return nil } func (x *FlowFields) GetIcmpInfo() *ICMPInfo { - if x, ok := x.GetConnectionInfo().(*FlowFields_IcmpInfo); ok { - return x.IcmpInfo + if x != nil { + if x, ok := x.ConnectionInfo.(*FlowFields_IcmpInfo); ok { + return x.IcmpInfo + } } return nil } @@ -443,6 +442,27 @@ func (x *FlowFields) GetDestResourceId() []byte { return nil } +func (x *FlowFields) GetNumOfStarts() uint64 { + if x != nil { + return x.NumOfStarts + } + return 0 +} + +func (x *FlowFields) GetNumOfEnds() uint64 { + if x != nil { + return x.NumOfEnds + } + return 0 +} + +func (x *FlowFields) GetNumOfDrops() uint64 { + if x != nil { + return x.NumOfDrops + } + return 0 +} + type isFlowFields_ConnectionInfo interface { isFlowFields_ConnectionInfo() } @@ -463,21 +483,18 @@ func (*FlowFields_IcmpInfo) isFlowFields_ConnectionInfo() {} // TCP/UDP port information type PortInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + SourcePort uint32 `protobuf:"varint,1,opt,name=source_port,json=sourcePort,proto3" json:"source_port,omitempty"` + DestPort uint32 `protobuf:"varint,2,opt,name=dest_port,json=destPort,proto3" json:"dest_port,omitempty"` unknownFields protoimpl.UnknownFields - - SourcePort uint32 `protobuf:"varint,1,opt,name=source_port,json=sourcePort,proto3" json:"source_port,omitempty"` - DestPort uint32 `protobuf:"varint,2,opt,name=dest_port,json=destPort,proto3" json:"dest_port,omitempty"` + sizeCache protoimpl.SizeCache } func (x *PortInfo) Reset() { *x = PortInfo{} - if protoimpl.UnsafeEnabled { - mi := &file_flow_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_flow_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *PortInfo) String() string { @@ -488,7 +505,7 @@ func (*PortInfo) ProtoMessage() {} func (x *PortInfo) ProtoReflect() protoreflect.Message { mi := &file_flow_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -519,21 +536,18 @@ func (x *PortInfo) GetDestPort() uint32 { // ICMP message information type ICMPInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + IcmpType uint32 `protobuf:"varint,1,opt,name=icmp_type,json=icmpType,proto3" json:"icmp_type,omitempty"` + IcmpCode uint32 `protobuf:"varint,2,opt,name=icmp_code,json=icmpCode,proto3" json:"icmp_code,omitempty"` unknownFields protoimpl.UnknownFields - - IcmpType uint32 `protobuf:"varint,1,opt,name=icmp_type,json=icmpType,proto3" json:"icmp_type,omitempty"` - IcmpCode uint32 `protobuf:"varint,2,opt,name=icmp_code,json=icmpCode,proto3" json:"icmp_code,omitempty"` + sizeCache protoimpl.SizeCache } func (x *ICMPInfo) Reset() { *x = ICMPInfo{} - if protoimpl.UnsafeEnabled { - mi := &file_flow_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_flow_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ICMPInfo) String() string { @@ -544,7 +558,7 @@ func (*ICMPInfo) ProtoMessage() {} func (x *ICMPInfo) ProtoReflect() protoreflect.Message { mi := &file_flow_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -575,102 +589,83 @@ func (x *ICMPInfo) GetIcmpCode() uint32 { var File_flow_proto protoreflect.FileDescriptor -var file_flow_proto_rawDesc = []byte{ - 0x0a, 0x0a, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x66, 0x6c, - 0x6f, 0x77, 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, 0x22, 0xd4, 0x01, 0x0a, 0x09, 0x46, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 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, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x66, 0x69, - 0x65, 0x6c, 0x64, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x66, 0x6c, 0x6f, - 0x77, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x0a, 0x66, 0x6c, - 0x6f, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x49, 0x6e, - 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, - 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x4b, 0x0a, 0x0c, 0x46, 0x6c, - 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, - 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x49, 0x6e, - 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x9c, 0x04, 0x0a, 0x0a, 0x46, 0x6c, 0x6f, 0x77, - 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x12, - 0x1e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, - 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, - 0x17, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x06, 0x72, 0x75, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x66, 0x6c, - 0x6f, 0x77, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, - 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x70, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x70, - 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x06, 0x64, 0x65, 0x73, 0x74, 0x49, 0x70, 0x12, 0x2d, 0x0a, 0x09, 0x70, 0x6f, 0x72, - 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x66, - 0x6c, 0x6f, 0x77, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x08, - 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2d, 0x0a, 0x09, 0x69, 0x63, 0x6d, 0x70, - 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x66, 0x6c, - 0x6f, 0x77, 0x2e, 0x49, 0x43, 0x4d, 0x50, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x08, 0x69, - 0x63, 0x6d, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x78, 0x5f, 0x70, 0x61, - 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x78, 0x50, - 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x78, 0x5f, 0x70, 0x61, 0x63, - 0x6b, 0x65, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x78, 0x50, 0x61, - 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x78, 0x5f, 0x62, 0x79, 0x74, 0x65, - 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x72, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, - 0x12, 0x19, 0x0a, 0x08, 0x74, 0x78, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x07, 0x74, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x73, - 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0f, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x49, 0x64, 0x42, 0x11, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x48, 0x0a, 0x08, 0x50, 0x6f, 0x72, 0x74, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x6f, 0x72, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, - 0x6f, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, - 0x22, 0x44, 0x0a, 0x08, 0x49, 0x43, 0x4d, 0x50, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, - 0x69, 0x63, 0x6d, 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x08, 0x69, 0x63, 0x6d, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x63, 0x6d, - 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x69, 0x63, - 0x6d, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x2a, 0x45, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, - 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, - 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x01, - 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, 0x44, 0x10, 0x02, 0x12, 0x0d, - 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x52, 0x4f, 0x50, 0x10, 0x03, 0x2a, 0x3b, 0x0a, - 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x44, 0x49, - 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, - 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x0a, - 0x0a, 0x06, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x02, 0x32, 0x42, 0x0a, 0x0b, 0x46, 0x6c, - 0x6f, 0x77, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x73, 0x12, 0x0f, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x12, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x46, 0x6c, 0x6f, 0x77, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x08, - 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} +const file_flow_proto_rawDesc = "" + + "\n" + + "\n" + + "flow.proto\x12\x04flow\x1a\x1fgoogle/protobuf/timestamp.proto\"\xd4\x01\n" + + "\tFlowEvent\x12\x19\n" + + "\bevent_id\x18\x01 \x01(\fR\aeventId\x128\n" + + "\ttimestamp\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\x12\x1d\n" + + "\n" + + "public_key\x18\x03 \x01(\fR\tpublicKey\x121\n" + + "\vflow_fields\x18\x04 \x01(\v2\x10.flow.FlowFieldsR\n" + + "flowFields\x12 \n" + + "\visInitiator\x18\x05 \x01(\bR\visInitiator\"K\n" + + "\fFlowEventAck\x12\x19\n" + + "\bevent_id\x18\x01 \x01(\fR\aeventId\x12 \n" + + "\visInitiator\x18\x02 \x01(\bR\visInitiator\"\x82\x05\n" + + "\n" + + "FlowFields\x12\x17\n" + + "\aflow_id\x18\x01 \x01(\fR\x06flowId\x12\x1e\n" + + "\x04type\x18\x02 \x01(\x0e2\n" + + ".flow.TypeR\x04type\x12\x17\n" + + "\arule_id\x18\x03 \x01(\fR\x06ruleId\x12-\n" + + "\tdirection\x18\x04 \x01(\x0e2\x0f.flow.DirectionR\tdirection\x12\x1a\n" + + "\bprotocol\x18\x05 \x01(\rR\bprotocol\x12\x1b\n" + + "\tsource_ip\x18\x06 \x01(\fR\bsourceIp\x12\x17\n" + + "\adest_ip\x18\a \x01(\fR\x06destIp\x12-\n" + + "\tport_info\x18\b \x01(\v2\x0e.flow.PortInfoH\x00R\bportInfo\x12-\n" + + "\ticmp_info\x18\t \x01(\v2\x0e.flow.ICMPInfoH\x00R\bicmpInfo\x12\x1d\n" + + "\n" + + "rx_packets\x18\n" + + " \x01(\x04R\trxPackets\x12\x1d\n" + + "\n" + + "tx_packets\x18\v \x01(\x04R\ttxPackets\x12\x19\n" + + "\brx_bytes\x18\f \x01(\x04R\arxBytes\x12\x19\n" + + "\btx_bytes\x18\r \x01(\x04R\atxBytes\x12,\n" + + "\x12source_resource_id\x18\x0e \x01(\fR\x10sourceResourceId\x12(\n" + + "\x10dest_resource_id\x18\x0f \x01(\fR\x0edestResourceId\x12\"\n" + + "\rnum_of_starts\x18\x10 \x01(\x04R\vnumOfStarts\x12\x1e\n" + + "\vnum_of_ends\x18\x11 \x01(\x04R\tnumOfEnds\x12 \n" + + "\fnum_of_drops\x18\x12 \x01(\x04R\n" + + "numOfDropsB\x11\n" + + "\x0fconnection_info\"H\n" + + "\bPortInfo\x12\x1f\n" + + "\vsource_port\x18\x01 \x01(\rR\n" + + "sourcePort\x12\x1b\n" + + "\tdest_port\x18\x02 \x01(\rR\bdestPort\"D\n" + + "\bICMPInfo\x12\x1b\n" + + "\ticmp_type\x18\x01 \x01(\rR\bicmpType\x12\x1b\n" + + "\ticmp_code\x18\x02 \x01(\rR\bicmpCode*E\n" + + "\x04Type\x12\x10\n" + + "\fTYPE_UNKNOWN\x10\x00\x12\x0e\n" + + "\n" + + "TYPE_START\x10\x01\x12\f\n" + + "\bTYPE_END\x10\x02\x12\r\n" + + "\tTYPE_DROP\x10\x03*;\n" + + "\tDirection\x12\x15\n" + + "\x11DIRECTION_UNKNOWN\x10\x00\x12\v\n" + + "\aINGRESS\x10\x01\x12\n" + + "\n" + + "\x06EGRESS\x10\x022B\n" + + "\vFlowService\x123\n" + + "\x06Events\x12\x0f.flow.FlowEvent\x1a\x12.flow.FlowEventAck\"\x00(\x010\x01B\bZ\x06/protob\x06proto3" var ( file_flow_proto_rawDescOnce sync.Once - file_flow_proto_rawDescData = file_flow_proto_rawDesc + file_flow_proto_rawDescData []byte ) func file_flow_proto_rawDescGZIP() []byte { file_flow_proto_rawDescOnce.Do(func() { - file_flow_proto_rawDescData = protoimpl.X.CompressGZIP(file_flow_proto_rawDescData) + file_flow_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_flow_proto_rawDesc), len(file_flow_proto_rawDesc))) }) return file_flow_proto_rawDescData } var file_flow_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_flow_proto_msgTypes = make([]protoimpl.MessageInfo, 5) -var file_flow_proto_goTypes = []interface{}{ +var file_flow_proto_goTypes = []any{ (Type)(0), // 0: flow.Type (Direction)(0), // 1: flow.Direction (*FlowEvent)(nil), // 2: flow.FlowEvent @@ -701,69 +696,7 @@ func file_flow_proto_init() { if File_flow_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_flow_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlowEvent); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_flow_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlowEventAck); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_flow_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlowFields); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_flow_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PortInfo); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_flow_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ICMPInfo); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_flow_proto_msgTypes[2].OneofWrappers = []interface{}{ + file_flow_proto_msgTypes[2].OneofWrappers = []any{ (*FlowFields_PortInfo)(nil), (*FlowFields_IcmpInfo)(nil), } @@ -771,7 +704,7 @@ func file_flow_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_flow_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_flow_proto_rawDesc), len(file_flow_proto_rawDesc)), NumEnums: 2, NumMessages: 5, NumExtensions: 0, @@ -783,7 +716,6 @@ func file_flow_proto_init() { MessageInfos: file_flow_proto_msgTypes, }.Build() File_flow_proto = out.File - file_flow_proto_rawDesc = nil file_flow_proto_goTypes = nil file_flow_proto_depIdxs = nil } diff --git a/flow/proto/flow.proto b/flow/proto/flow.proto index ff5c502822a..ec207d2f0ef 100644 --- a/flow/proto/flow.proto +++ b/flow/proto/flow.proto @@ -75,6 +75,9 @@ message FlowFields { bytes source_resource_id = 14; bytes dest_resource_id = 15; + uint64 num_of_starts = 16; + uint64 num_of_ends = 17; + uint64 num_of_drops = 18; } // Flow event types diff --git a/flow/proto/flow_grpc.pb.go b/flow/proto/flow_grpc.pb.go index b790f86a263..fa3f63152e8 100644 --- a/flow/proto/flow_grpc.pb.go +++ b/flow/proto/flow_grpc.pb.go @@ -1,4 +1,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.2 +// - protoc v7.35.0 +// source: flow.proto package proto @@ -11,15 +15,19 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + FlowService_Events_FullMethodName = "/flow.FlowService/Events" +) // FlowServiceClient is the client API for FlowService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type FlowServiceClient interface { // Client to receiver streams of events and acknowledgements - Events(ctx context.Context, opts ...grpc.CallOption) (FlowService_EventsClient, error) + Events(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[FlowEvent, FlowEventAck], error) } type flowServiceClient struct { @@ -30,54 +38,40 @@ func NewFlowServiceClient(cc grpc.ClientConnInterface) FlowServiceClient { return &flowServiceClient{cc} } -func (c *flowServiceClient) Events(ctx context.Context, opts ...grpc.CallOption) (FlowService_EventsClient, error) { - stream, err := c.cc.NewStream(ctx, &FlowService_ServiceDesc.Streams[0], "/flow.FlowService/Events", opts...) +func (c *flowServiceClient) Events(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[FlowEvent, FlowEventAck], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &FlowService_ServiceDesc.Streams[0], FlowService_Events_FullMethodName, cOpts...) if err != nil { return nil, err } - x := &flowServiceEventsClient{stream} + x := &grpc.GenericClientStream[FlowEvent, FlowEventAck]{ClientStream: stream} return x, nil } -type FlowService_EventsClient interface { - Send(*FlowEvent) error - Recv() (*FlowEventAck, error) - grpc.ClientStream -} - -type flowServiceEventsClient struct { - grpc.ClientStream -} - -func (x *flowServiceEventsClient) Send(m *FlowEvent) error { - return x.ClientStream.SendMsg(m) -} - -func (x *flowServiceEventsClient) Recv() (*FlowEventAck, error) { - m := new(FlowEventAck) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type FlowService_EventsClient = grpc.BidiStreamingClient[FlowEvent, FlowEventAck] // FlowServiceServer is the server API for FlowService service. // All implementations must embed UnimplementedFlowServiceServer -// for forward compatibility +// for forward compatibility. type FlowServiceServer interface { // Client to receiver streams of events and acknowledgements - Events(FlowService_EventsServer) error + Events(grpc.BidiStreamingServer[FlowEvent, FlowEventAck]) error mustEmbedUnimplementedFlowServiceServer() } -// UnimplementedFlowServiceServer must be embedded to have forward compatible implementations. -type UnimplementedFlowServiceServer struct { -} +// UnimplementedFlowServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedFlowServiceServer struct{} -func (UnimplementedFlowServiceServer) Events(FlowService_EventsServer) error { - return status.Errorf(codes.Unimplemented, "method Events not implemented") +func (UnimplementedFlowServiceServer) Events(grpc.BidiStreamingServer[FlowEvent, FlowEventAck]) error { + return status.Error(codes.Unimplemented, "method Events not implemented") } func (UnimplementedFlowServiceServer) mustEmbedUnimplementedFlowServiceServer() {} +func (UnimplementedFlowServiceServer) testEmbeddedByValue() {} // UnsafeFlowServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to FlowServiceServer will @@ -87,34 +81,22 @@ type UnsafeFlowServiceServer interface { } func RegisterFlowServiceServer(s grpc.ServiceRegistrar, srv FlowServiceServer) { + // If the following call panics, it indicates UnimplementedFlowServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&FlowService_ServiceDesc, srv) } func _FlowService_Events_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(FlowServiceServer).Events(&flowServiceEventsServer{stream}) -} - -type FlowService_EventsServer interface { - Send(*FlowEventAck) error - Recv() (*FlowEvent, error) - grpc.ServerStream -} - -type flowServiceEventsServer struct { - grpc.ServerStream + return srv.(FlowServiceServer).Events(&grpc.GenericServerStream[FlowEvent, FlowEventAck]{ServerStream: stream}) } -func (x *flowServiceEventsServer) Send(m *FlowEventAck) error { - return x.ServerStream.SendMsg(m) -} - -func (x *flowServiceEventsServer) Recv() (*FlowEvent, error) { - m := new(FlowEvent) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type FlowService_EventsServer = grpc.BidiStreamingServer[FlowEvent, FlowEventAck] // FlowService_ServiceDesc is the grpc.ServiceDesc for FlowService service. // It's only intended for direct use with grpc.RegisterService, From 42e0007f4a3cf785cf43a8ce2d7981d7176ae297 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Thu, 11 Jun 2026 10:18:08 +0200 Subject: [PATCH 06/30] fixes based on sonarcube checks Signed-off-by: Dmitri --- client/internal/netflow/store/memory.go | 84 ++++++++++++------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index f1a216348b7..321a9b81fde 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -8,7 +8,6 @@ import ( "time" "github.com/google/uuid" - "github.com/netbirdio/netbird/client/internal/netflow/types" ) @@ -76,56 +75,57 @@ type aggregationKey struct { destPort uint16 protocol uint8 icmpType uint8 - ts int64 // used to prevent aggregation on non icmp/udp/tcp events + unique int64 // used to prevent aggregation on non icmp/udp/tcp events } func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { aggregated := make(map[aggregationKey]*types.Event) for _, v := range am.events { lookupKey := aggregationKey{destAddr: v.DestIP, destPort: v.DestPort, protocol: uint8(v.Protocol), icmpType: v.ICMPCode} - if aggregatedEvent, ok := aggregated[lookupKey]; ok { - switch aggregatedEvent.Protocol { - case types.ICMP, types.ICMPv6, types.UDP, types.TCP: - // track the number of connections, duration?, open and close events? - aggregatedEvent.RxBytes += v.RxBytes - aggregatedEvent.RxPackets += v.RxPackets - aggregatedEvent.TxBytes += v.TxBytes - aggregatedEvent.TxPackets += v.TxPackets - switch v.Type { - case types.TypeStart: - aggregatedEvent.NumOfStarts += 1 - case types.TypeDrop: - aggregatedEvent.NumOfDrops += 1 - case types.TypeEnd: - aggregatedEvent.NumOfEnds += 1 - } - if aggregatedEvent.Timestamp.Compare(v.Timestamp) > 0 { - aggregatedEvent.Timestamp = v.Timestamp - aggregatedEvent.ID = v.ID - aggregatedEvent.Type = v.Type - } - // do we aggregate icmp by code? - default: - // shouldn't get here + if _, ok := aggregated[lookupKey]; !ok { + aggregated[lookupKey] = v.Clone() + event := aggregated[lookupKey] + + if event.Protocol != types.ICMP && event.Protocol != types.ICMPv6 && event.Protocol != types.UDP && event.Protocol != types.TCP { + lookupKey.unique = time.Now().UnixNano() // to make the lookup key unique so we don't aggregate on it + continue } - } else { - switch v.Protocol { - case types.ICMP, types.ICMPv6, types.TCP, types.UDP: - event := v.Clone() - aggregated[lookupKey] = event - switch event.Type { - case types.TypeStart: - event.NumOfStarts += 1 - case types.TypeDrop: - event.NumOfDrops += 1 - case types.TypeEnd: - event.NumOfEnds += 1 - } - default: - lookupKey.ts = time.Now().UnixNano() // to make the lookup key unique so we don't aggregate on it - aggregated[lookupKey] = v.Clone() + + switch event.Type { + case types.TypeStart: + event.NumOfStarts += 1 + case types.TypeDrop: + event.NumOfDrops += 1 + case types.TypeEnd: + event.NumOfEnds += 1 } + continue + } + + aggregatedEvent := aggregated[lookupKey] + if aggregatedEvent.Protocol != types.ICMP && aggregatedEvent.Protocol != types.ICMPv6 && aggregatedEvent.Protocol != types.UDP && aggregatedEvent.Protocol != types.TCP { + continue // we don't aggregate this type of events; shouldn't ever get here + } + + // track the number of connections, duration?, open and close events? + aggregatedEvent.RxBytes += v.RxBytes + aggregatedEvent.RxPackets += v.RxPackets + aggregatedEvent.TxBytes += v.TxBytes + aggregatedEvent.TxPackets += v.TxPackets + switch v.Type { + case types.TypeStart: + aggregatedEvent.NumOfStarts += 1 + case types.TypeDrop: + aggregatedEvent.NumOfDrops += 1 + case types.TypeEnd: + aggregatedEvent.NumOfEnds += 1 + } + if aggregatedEvent.Timestamp.Compare(v.Timestamp) > 0 { + aggregatedEvent.Timestamp = v.Timestamp + aggregatedEvent.ID = v.ID + aggregatedEvent.Type = v.Type } + // do we aggregate icmp by code? } return slices.Collect(maps.Values(aggregated)) // could return an iterator instead here From 12a8943b992c94865b971f6ef1b683bed8f78f7e Mon Sep 17 00:00:00 2001 From: Dmitri Date: Thu, 11 Jun 2026 12:03:46 +0200 Subject: [PATCH 07/30] regenerated proto files Signed-off-by: Dmitri --- client/internal/netflow/manager.go | 8 +- flow/proto/flow.pb.go | 2 +- flow/proto/flow_grpc.pb.go | 4 +- flow/proto/generate.sh | 5 +- flow/proto/google/protobuf/any.proto | 162 ++ flow/proto/google/protobuf/api.proto | 229 +++ .../google/protobuf/compiler/plugin.proto | 180 ++ flow/proto/google/protobuf/cpp_features.proto | 67 + flow/proto/google/protobuf/descriptor.proto | 1448 +++++++++++++++++ flow/proto/google/protobuf/duration.proto | 115 ++ flow/proto/google/protobuf/empty.proto | 51 + flow/proto/google/protobuf/field_mask.proto | 243 +++ flow/proto/google/protobuf/go_features.proto | 112 ++ .../proto/google/protobuf/java_features.proto | 132 ++ .../google/protobuf/source_context.proto | 48 + flow/proto/google/protobuf/struct.proto | 95 ++ flow/proto/google/protobuf/timestamp.proto | 145 ++ flow/proto/google/protobuf/type.proto | 217 +++ flow/proto/google/protobuf/wrappers.proto | 157 ++ 19 files changed, 3413 insertions(+), 7 deletions(-) create mode 100644 flow/proto/google/protobuf/any.proto create mode 100644 flow/proto/google/protobuf/api.proto create mode 100644 flow/proto/google/protobuf/compiler/plugin.proto create mode 100644 flow/proto/google/protobuf/cpp_features.proto create mode 100644 flow/proto/google/protobuf/descriptor.proto create mode 100644 flow/proto/google/protobuf/duration.proto create mode 100644 flow/proto/google/protobuf/empty.proto create mode 100644 flow/proto/google/protobuf/field_mask.proto create mode 100644 flow/proto/google/protobuf/go_features.proto create mode 100644 flow/proto/google/protobuf/java_features.proto create mode 100644 flow/proto/google/protobuf/source_context.proto create mode 100644 flow/proto/google/protobuf/struct.proto create mode 100644 flow/proto/google/protobuf/timestamp.proto create mode 100644 flow/proto/google/protobuf/type.proto create mode 100644 flow/proto/google/protobuf/wrappers.proto diff --git a/client/internal/netflow/manager.go b/client/internal/netflow/manager.go index d6669f9ac15..869bddb7a62 100644 --- a/client/internal/netflow/manager.go +++ b/client/internal/netflow/manager.go @@ -266,10 +266,14 @@ func (m *Manager) startRetries(ctx context.Context) { case <-ctx.Done(): return case <-ticker.C: - // TODO: grace period on retries to avoid early retries? for _, e := range m.eventsWithoutAcks.GetEvents() { + if e.Timestamp.Add(time.Second).After(time.Now()) { + // grace period on retries to avoid early retries + // do not retry if the event is less than 1 sec old + continue + } if err := m.send(e); err != nil { - ticker = time.NewTimer(retryBackoff.NextBackOff()) + ticker = time.NewTimer(retryBackoff.NextBackOff()) //nolint:staticcheck break } } diff --git a/flow/proto/flow.pb.go b/flow/proto/flow.pb.go index ca4ccc42858..955a6e02648 100644 --- a/flow/proto/flow.pb.go +++ b/flow/proto/flow.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.11 -// protoc v7.35.0 +// protoc v7.34.1 // source: flow.proto package proto diff --git a/flow/proto/flow_grpc.pb.go b/flow/proto/flow_grpc.pb.go index fa3f63152e8..7f34aa317d6 100644 --- a/flow/proto/flow_grpc.pb.go +++ b/flow/proto/flow_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.6.2 -// - protoc v7.35.0 +// - protoc-gen-go-grpc v1.6.1 +// - protoc v7.34.1 // source: flow.proto package proto diff --git a/flow/proto/generate.sh b/flow/proto/generate.sh index 6bbf78e61ae..f2937399a0b 100755 --- a/flow/proto/generate.sh +++ b/flow/proto/generate.sh @@ -10,8 +10,9 @@ fi old_pwd=$(pwd) script_path=$(dirname $(realpath "$0")) +echo "$script_path" cd "$script_path" -go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26 -go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1 +#go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26 +#go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1 protoc -I ./ ./flow.proto --go_out=../ --go-grpc_out=../ cd "$old_pwd" diff --git a/flow/proto/google/protobuf/any.proto b/flow/proto/google/protobuf/any.proto new file mode 100644 index 00000000000..eff44e5099d --- /dev/null +++ b/flow/proto/google/protobuf/any.proto @@ -0,0 +1,162 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option go_package = "google.golang.org/protobuf/types/known/anypb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "AnyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// // or ... +// if (any.isSameTypeAs(Foo.getDefaultInstance())) { +// foo = any.unpack(Foo.getDefaultInstance()); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := anypb.New(foo) +// if err != nil { +// ... +// } +// ... +// foo := &pb.Foo{} +// if err := any.UnmarshalTo(foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +message Any { + // A URL/resource name that uniquely identifies the type of the serialized + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent + // the fully qualified name of the type (as in + // `path/google.protobuf.Duration`). The name should be in a canonical form + // (e.g., leading "." is not accepted). + // + // In practice, teams usually precompile into the binary all types that they + // expect it to use in the context of Any. However, for URLs which use the + // scheme `http`, `https`, or no scheme, one can optionally set up a type + // server that maps type URLs to message definitions as follows: + // + // * If no scheme is provided, `https` is assumed. + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Note: this functionality is not currently available in the official + // protobuf release, and it is not used for type URLs beginning with + // type.googleapis.com. As of May 2023, there are no widely used type server + // implementations and no plans to implement one. + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + string type_url = 1; + + // Must be a valid serialized protocol buffer of the above specified type. + bytes value = 2; +} diff --git a/flow/proto/google/protobuf/api.proto b/flow/proto/google/protobuf/api.proto new file mode 100644 index 00000000000..c8f742543c7 --- /dev/null +++ b/flow/proto/google/protobuf/api.proto @@ -0,0 +1,229 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +import "google/protobuf/source_context.proto"; +import "google/protobuf/type.proto"; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "ApiProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "google.golang.org/protobuf/types/known/apipb"; + +// Api is a light-weight descriptor for an API Interface. +// +// Interfaces are also described as "protocol buffer services" in some contexts, +// such as by the "service" keyword in a .proto file, but they are different +// from API Services, which represent a concrete implementation of an interface +// as opposed to simply a description of methods and bindings. They are also +// sometimes simply referred to as "APIs" in other contexts, such as the name of +// this message itself. See https://cloud.google.com/apis/design/glossary for +// detailed terminology. +// +// New usages of this message as an alternative to ServiceDescriptorProto are +// strongly discouraged. This message does not reliability preserve all +// information necessary to model the schema and preserve semantics. Instead +// make use of FileDescriptorSet which preserves the necessary information. +message Api { + // The fully qualified name of this interface, including package name + // followed by the interface's simple name. + string name = 1; + + // The methods of this interface, in unspecified order. + repeated Method methods = 2; + + // Any metadata attached to the interface. + repeated Option options = 3; + + // A version string for this interface. If specified, must have the form + // `major-version.minor-version`, as in `1.10`. If the minor version is + // omitted, it defaults to zero. If the entire version field is empty, the + // major version is derived from the package name, as outlined below. If the + // field is not empty, the version in the package name will be verified to be + // consistent with what is provided here. + // + // The versioning schema uses [semantic + // versioning](http://semver.org) where the major version number + // indicates a breaking change and the minor version an additive, + // non-breaking change. Both version numbers are signals to users + // what to expect from different versions, and should be carefully + // chosen based on the product plan. + // + // The major version is also reflected in the package name of the + // interface, which must end in `v`, as in + // `google.feature.v1`. For major versions 0 and 1, the suffix can + // be omitted. Zero major versions must only be used for + // experimental, non-GA interfaces. + // + string version = 4; + + // Source context for the protocol buffer service represented by this + // message. + SourceContext source_context = 5; + + // Included interfaces. See [Mixin][]. + repeated Mixin mixins = 6; + + // The source syntax of the service. + Syntax syntax = 7; + + // The source edition string, only valid when syntax is SYNTAX_EDITIONS. + string edition = 8; +} + +// Method represents a method of an API interface. +// +// New usages of this message as an alternative to MethodDescriptorProto are +// strongly discouraged. This message does not reliability preserve all +// information necessary to model the schema and preserve semantics. Instead +// make use of FileDescriptorSet which preserves the necessary information. +message Method { + // The simple name of this method. + string name = 1; + + // A URL of the input message type. + string request_type_url = 2; + + // If true, the request is streamed. + bool request_streaming = 3; + + // The URL of the output message type. + string response_type_url = 4; + + // If true, the response is streamed. + bool response_streaming = 5; + + // Any metadata attached to the method. + repeated Option options = 6; + + // The source syntax of this method. + // + // This field should be ignored, instead the syntax should be inherited from + // Api. This is similar to Field and EnumValue. + Syntax syntax = 7 [deprecated = true]; + + // The source edition string, only valid when syntax is SYNTAX_EDITIONS. + // + // This field should be ignored, instead the edition should be inherited from + // Api. This is similar to Field and EnumValue. + string edition = 8 [deprecated = true]; +} + +// Declares an API Interface to be included in this interface. The including +// interface must redeclare all the methods from the included interface, but +// documentation and options are inherited as follows: +// +// - If after comment and whitespace stripping, the documentation +// string of the redeclared method is empty, it will be inherited +// from the original method. +// +// - Each annotation belonging to the service config (http, +// visibility) which is not set in the redeclared method will be +// inherited. +// +// - If an http annotation is inherited, the path pattern will be +// modified as follows. Any version prefix will be replaced by the +// version of the including interface plus the [root][] path if +// specified. +// +// Example of a simple mixin: +// +// package google.acl.v1; +// service AccessControl { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v1/{resource=**}:getAcl"; +// } +// } +// +// package google.storage.v2; +// service Storage { +// rpc GetAcl(GetAclRequest) returns (Acl); +// +// // Get a data record. +// rpc GetData(GetDataRequest) returns (Data) { +// option (google.api.http).get = "/v2/{resource=**}"; +// } +// } +// +// Example of a mixin configuration: +// +// apis: +// - name: google.storage.v2.Storage +// mixins: +// - name: google.acl.v1.AccessControl +// +// The mixin construct implies that all methods in `AccessControl` are +// also declared with same name and request/response types in +// `Storage`. A documentation generator or annotation processor will +// see the effective `Storage.GetAcl` method after inheriting +// documentation and annotations as follows: +// +// service Storage { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v2/{resource=**}:getAcl"; +// } +// ... +// } +// +// Note how the version in the path pattern changed from `v1` to `v2`. +// +// If the `root` field in the mixin is specified, it should be a +// relative path under which inherited HTTP paths are placed. Example: +// +// apis: +// - name: google.storage.v2.Storage +// mixins: +// - name: google.acl.v1.AccessControl +// root: acls +// +// This implies the following inherited HTTP annotation: +// +// service Storage { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; +// } +// ... +// } +message Mixin { + // The fully qualified name of the interface which is included. + string name = 1; + + // If non-empty specifies a path under which inherited HTTP paths + // are rooted. + string root = 2; +} diff --git a/flow/proto/google/protobuf/compiler/plugin.proto b/flow/proto/google/protobuf/compiler/plugin.proto new file mode 100644 index 00000000000..10d285f8a54 --- /dev/null +++ b/flow/proto/google/protobuf/compiler/plugin.proto @@ -0,0 +1,180 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// Author: kenton@google.com (Kenton Varda) +// +// protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is +// just a program that reads a CodeGeneratorRequest from stdin and writes a +// CodeGeneratorResponse to stdout. +// +// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead +// of dealing with the raw protocol defined here. +// +// A plugin executable needs only to be placed somewhere in the path. The +// plugin should be named "protoc-gen-$NAME", and will then be used when the +// flag "--${NAME}_out" is passed to protoc. + +syntax = "proto2"; + +package google.protobuf.compiler; +option java_package = "com.google.protobuf.compiler"; +option java_outer_classname = "PluginProtos"; + +import "google/protobuf/descriptor.proto"; + +option csharp_namespace = "Google.Protobuf.Compiler"; +option go_package = "google.golang.org/protobuf/types/pluginpb"; + +// The version number of protocol compiler. +message Version { + optional int32 major = 1; + optional int32 minor = 2; + optional int32 patch = 3; + // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should + // be empty for mainline stable releases. + optional string suffix = 4; +} + +// An encoded CodeGeneratorRequest is written to the plugin's stdin. +message CodeGeneratorRequest { + // The .proto files that were explicitly listed on the command-line. The + // code generator should generate code only for these files. Each file's + // descriptor will be included in proto_file, below. + repeated string file_to_generate = 1; + + // The generator parameter passed on the command-line. + optional string parameter = 2; + + // FileDescriptorProtos for all files in files_to_generate and everything + // they import. The files will appear in topological order, so each file + // appears before any file that imports it. + // + // Note: the files listed in files_to_generate will include runtime-retention + // options only, but all other files will include source-retention options. + // The source_file_descriptors field below is available in case you need + // source-retention options for files_to_generate. + // + // protoc guarantees that all proto_files will be written after + // the fields above, even though this is not technically guaranteed by the + // protobuf wire format. This theoretically could allow a plugin to stream + // in the FileDescriptorProtos and handle them one by one rather than read + // the entire set into memory at once. However, as of this writing, this + // is not similarly optimized on protoc's end -- it will store all fields in + // memory at once before sending them to the plugin. + // + // Type names of fields and extensions in the FileDescriptorProto are always + // fully qualified. + repeated FileDescriptorProto proto_file = 15; + + // File descriptors with all options, including source-retention options. + // These descriptors are only provided for the files listed in + // files_to_generate. + repeated FileDescriptorProto source_file_descriptors = 17; + + // The version number of protocol compiler. + optional Version compiler_version = 3; +} + +// The plugin writes an encoded CodeGeneratorResponse to stdout. +message CodeGeneratorResponse { + // Error message. If non-empty, code generation failed. The plugin process + // should exit with status code zero even if it reports an error in this way. + // + // This should be used to indicate errors in .proto files which prevent the + // code generator from generating correct code. Errors which indicate a + // problem in protoc itself -- such as the input CodeGeneratorRequest being + // unparseable -- should be reported by writing a message to stderr and + // exiting with a non-zero status code. + optional string error = 1; + + // A bitmask of supported features that the code generator supports. + // This is a bitwise "or" of values from the Feature enum. + optional uint64 supported_features = 2; + + // Sync with code_generator.h. + enum Feature { + FEATURE_NONE = 0; + FEATURE_PROTO3_OPTIONAL = 1; + FEATURE_SUPPORTS_EDITIONS = 2; + } + + // The minimum edition this plugin supports. This will be treated as an + // Edition enum, but we want to allow unknown values. It should be specified + // according the edition enum value, *not* the edition number. Only takes + // effect for plugins that have FEATURE_SUPPORTS_EDITIONS set. + optional int32 minimum_edition = 3; + + // The maximum edition this plugin supports. This will be treated as an + // Edition enum, but we want to allow unknown values. It should be specified + // according the edition enum value, *not* the edition number. Only takes + // effect for plugins that have FEATURE_SUPPORTS_EDITIONS set. + optional int32 maximum_edition = 4; + + // Represents a single generated file. + message File { + // The file name, relative to the output directory. The name must not + // contain "." or ".." components and must be relative, not be absolute (so, + // the file cannot lie outside the output directory). "/" must be used as + // the path separator, not "\". + // + // If the name is omitted, the content will be appended to the previous + // file. This allows the generator to break large files into small chunks, + // and allows the generated text to be streamed back to protoc so that large + // files need not reside completely in memory at one time. Note that as of + // this writing protoc does not optimize for this -- it will read the entire + // CodeGeneratorResponse before writing files to disk. + optional string name = 1; + + // If non-empty, indicates that the named file should already exist, and the + // content here is to be inserted into that file at a defined insertion + // point. This feature allows a code generator to extend the output + // produced by another code generator. The original generator may provide + // insertion points by placing special annotations in the file that look + // like: + // @@protoc_insertion_point(NAME) + // The annotation can have arbitrary text before and after it on the line, + // which allows it to be placed in a comment. NAME should be replaced with + // an identifier naming the point -- this is what other generators will use + // as the insertion_point. Code inserted at this point will be placed + // immediately above the line containing the insertion point (thus multiple + // insertions to the same point will come out in the order they were added). + // The double-@ is intended to make it unlikely that the generated code + // could contain things that look like insertion points by accident. + // + // For example, the C++ code generator places the following line in the + // .pb.h files that it generates: + // // @@protoc_insertion_point(namespace_scope) + // This line appears within the scope of the file's package namespace, but + // outside of any particular class. Another plugin can then specify the + // insertion_point "namespace_scope" to generate additional classes or + // other declarations that should be placed in this scope. + // + // Note that if the line containing the insertion point begins with + // whitespace, the same whitespace will be added to every line of the + // inserted text. This is useful for languages like Python, where + // indentation matters. In these languages, the insertion point comment + // should be indented the same amount as any inserted code will need to be + // in order to work correctly in that context. + // + // The code generator that generates the initial file and the one which + // inserts into it must both run as part of a single invocation of protoc. + // Code generators are executed in the order in which they appear on the + // command line. + // + // If |insertion_point| is present, |name| must also be present. + optional string insertion_point = 2; + + // The file contents. + optional string content = 15; + + // Information describing the file content being inserted. If an insertion + // point is used, this information will be appropriately offset and inserted + // into the code generation metadata for the generated files. + optional GeneratedCodeInfo generated_code_info = 16; + } + repeated File file = 15; +} diff --git a/flow/proto/google/protobuf/cpp_features.proto b/flow/proto/google/protobuf/cpp_features.proto new file mode 100644 index 00000000000..75bf6b859af --- /dev/null +++ b/flow/proto/google/protobuf/cpp_features.proto @@ -0,0 +1,67 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +syntax = "proto2"; + +package pb; + +import "google/protobuf/descriptor.proto"; + +extend google.protobuf.FeatureSet { + optional CppFeatures cpp = 1000; +} + +message CppFeatures { + // Whether or not to treat an enum field as closed. This option is only + // applicable to enum fields, and will be removed in the future. It is + // consistent with the legacy behavior of using proto3 enum types for proto2 + // fields. + optional bool legacy_closed_enum = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + edition_deprecated: EDITION_2023, + deprecation_warning: "The legacy closed enum behavior in C++ is " + "deprecated and is scheduled to be removed in " + "edition 2025. See http://protobuf.dev/programming-guides/enum/#cpp for " + "more information", + }, + edition_defaults = { edition: EDITION_LEGACY, value: "true" }, + edition_defaults = { edition: EDITION_PROTO3, value: "false" } + ]; + + enum StringType { + STRING_TYPE_UNKNOWN = 0; + VIEW = 1; + CORD = 2; + STRING = 3; + } + + optional StringType string_type = 2 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "STRING" }, + edition_defaults = { edition: EDITION_2024, value: "VIEW" } + ]; + + optional bool enum_name_uses_string_view = 3 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2024, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "false" }, + edition_defaults = { edition: EDITION_2024, value: "true" } + ]; +} diff --git a/flow/proto/google/protobuf/descriptor.proto b/flow/proto/google/protobuf/descriptor.proto new file mode 100644 index 00000000000..e5683a271ea --- /dev/null +++ b/flow/proto/google/protobuf/descriptor.proto @@ -0,0 +1,1448 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// The messages in this file describe the definitions found in .proto files. +// A valid .proto file can be translated directly to a FileDescriptorProto +// without any other information (e.g. without reading its imports). + +syntax = "proto2"; + +package google.protobuf; + +option go_package = "google.golang.org/protobuf/types/descriptorpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DescriptorProtos"; +option csharp_namespace = "Google.Protobuf.Reflection"; +option objc_class_prefix = "GPB"; +option cc_enable_arenas = true; + +// descriptor.proto must be optimized for speed because reflection-based +// algorithms don't work during bootstrapping. +option optimize_for = SPEED; + +// The protocol compiler can output a FileDescriptorSet containing the .proto +// files it parses. +message FileDescriptorSet { + repeated FileDescriptorProto file = 1; + + // Extensions for tooling. + extensions 536000000 [declaration = { + number: 536000000 + type: ".buf.descriptor.v1.FileDescriptorSetExtension" + full_name: ".buf.descriptor.v1.buf_file_descriptor_set_extension" + }]; +} + +// The full set of known editions. +enum Edition { + // A placeholder for an unknown edition value. + EDITION_UNKNOWN = 0; + + // A placeholder edition for specifying default behaviors *before* a feature + // was first introduced. This is effectively an "infinite past". + EDITION_LEGACY = 900; + + // Legacy syntax "editions". These pre-date editions, but behave much like + // distinct editions. These can't be used to specify the edition of proto + // files, but feature definitions must supply proto2/proto3 defaults for + // backwards compatibility. + EDITION_PROTO2 = 998; + EDITION_PROTO3 = 999; + + // Editions that have been released. The specific values are arbitrary and + // should not be depended on, but they will always be time-ordered for easy + // comparison. + EDITION_2023 = 1000; + EDITION_2024 = 1001; + + // A placeholder edition for developing and testing unscheduled features. + EDITION_UNSTABLE = 9999; + + // Placeholder editions for testing feature resolution. These should not be + // used or relied on outside of tests. + EDITION_1_TEST_ONLY = 1; + EDITION_2_TEST_ONLY = 2; + EDITION_99997_TEST_ONLY = 99997; + EDITION_99998_TEST_ONLY = 99998; + EDITION_99999_TEST_ONLY = 99999; + + // Placeholder for specifying unbounded edition support. This should only + // ever be used by plugins that can expect to never require any changes to + // support a new edition. + EDITION_MAX = 0x7FFFFFFF; +} + +// Describes a complete .proto file. +message FileDescriptorProto { + optional string name = 1; // file name, relative to root of source tree + optional string package = 2; // e.g. "foo", "foo.bar", etc. + + // Names of files imported by this file. + repeated string dependency = 3; + // Indexes of the public imported files in the dependency list above. + repeated int32 public_dependency = 10; + // Indexes of the weak imported files in the dependency list. + // For Google-internal migration only. Do not use. + repeated int32 weak_dependency = 11; + + // Names of files imported by this file purely for the purpose of providing + // option extensions. These are excluded from the dependency list above. + repeated string option_dependency = 15; + + // All top-level definitions in this file. + repeated DescriptorProto message_type = 4; + repeated EnumDescriptorProto enum_type = 5; + repeated ServiceDescriptorProto service = 6; + repeated FieldDescriptorProto extension = 7; + + optional FileOptions options = 8; + + // This field contains optional information about the original source code. + // You may safely remove this entire field without harming runtime + // functionality of the descriptors -- the information is needed only by + // development tools. + optional SourceCodeInfo source_code_info = 9; + + // The syntax of the proto file. + // The supported values are "proto2", "proto3", and "editions". + // + // If `edition` is present, this value must be "editions". + // WARNING: This field should only be used by protobuf plugins or special + // cases like the proto compiler. Other uses are discouraged and + // developers should rely on the protoreflect APIs for their client language. + optional string syntax = 12; + + // The edition of the proto file. + // WARNING: This field should only be used by protobuf plugins or special + // cases like the proto compiler. Other uses are discouraged and + // developers should rely on the protoreflect APIs for their client language. + optional Edition edition = 14; +} + +// Describes a message type. +message DescriptorProto { + optional string name = 1; + + repeated FieldDescriptorProto field = 2; + repeated FieldDescriptorProto extension = 6; + + repeated DescriptorProto nested_type = 3; + repeated EnumDescriptorProto enum_type = 4; + + message ExtensionRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + + optional ExtensionRangeOptions options = 3; + } + repeated ExtensionRange extension_range = 5; + + repeated OneofDescriptorProto oneof_decl = 8; + + optional MessageOptions options = 7; + + // Range of reserved tag numbers. Reserved tag numbers may not be used by + // fields or extension ranges in the same message. Reserved ranges may + // not overlap. + message ReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + } + repeated ReservedRange reserved_range = 9; + // Reserved field names, which may not be used by fields in the same message. + // A given name may only be reserved once. + repeated string reserved_name = 10; + + // Support for `export` and `local` keywords on enums. + optional SymbolVisibility visibility = 11; +} + +message ExtensionRangeOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + message Declaration { + // The extension number declared within the extension range. + optional int32 number = 1; + + // The fully-qualified name of the extension field. There must be a leading + // dot in front of the full name. + optional string full_name = 2; + + // The fully-qualified type name of the extension field. Unlike + // Metadata.type, Declaration.type must have a leading dot for messages + // and enums. + optional string type = 3; + + // If true, indicates that the number is reserved in the extension range, + // and any extension field with the number will fail to compile. Set this + // when a declared extension field is deleted. + optional bool reserved = 5; + + // If true, indicates that the extension must be defined as repeated. + // Otherwise the extension must be defined as optional. + optional bool repeated = 6; + + reserved 4; // removed is_repeated + } + + // For external users: DO NOT USE. We are in the process of open sourcing + // extension declaration and executing internal cleanups before it can be + // used externally. + repeated Declaration declaration = 2 [retention = RETENTION_SOURCE]; + + // Any features defined in the specific edition. + optional FeatureSet features = 50; + + // The verification state of the extension range. + enum VerificationState { + // All the extensions of the range must be declared. + DECLARATION = 0; + UNVERIFIED = 1; + } + + // The verification state of the range. + // TODO: flip the default to DECLARATION once all empty ranges + // are marked as UNVERIFIED. + optional VerificationState verification = 3 + [default = UNVERIFIED, retention = RETENTION_SOURCE]; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +// Describes a field within a message. +message FieldDescriptorProto { + enum Type { + // 0 is reserved for errors. + // Order is weird for historical reasons. + TYPE_DOUBLE = 1; + TYPE_FLOAT = 2; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if + // negative values are likely. + TYPE_INT64 = 3; + TYPE_UINT64 = 4; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if + // negative values are likely. + TYPE_INT32 = 5; + TYPE_FIXED64 = 6; + TYPE_FIXED32 = 7; + TYPE_BOOL = 8; + TYPE_STRING = 9; + // Tag-delimited aggregate. + // Group type is deprecated and not supported after google.protobuf. However, Proto3 + // implementations should still be able to parse the group wire format and + // treat group fields as unknown fields. In Editions, the group wire format + // can be enabled via the `message_encoding` feature. + TYPE_GROUP = 10; + TYPE_MESSAGE = 11; // Length-delimited aggregate. + + // New in version 2. + TYPE_BYTES = 12; + TYPE_UINT32 = 13; + TYPE_ENUM = 14; + TYPE_SFIXED32 = 15; + TYPE_SFIXED64 = 16; + TYPE_SINT32 = 17; // Uses ZigZag encoding. + TYPE_SINT64 = 18; // Uses ZigZag encoding. + } + + enum Label { + // 0 is reserved for errors + LABEL_OPTIONAL = 1; + LABEL_REPEATED = 3; + // The required label is only allowed in google.protobuf. In proto3 and Editions + // it's explicitly prohibited. In Editions, the `field_presence` feature + // can be used to get this behavior. + LABEL_REQUIRED = 2; + } + + optional string name = 1; + optional int32 number = 3; + optional Label label = 4; + + // If type_name is set, this need not be set. If both this and type_name + // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. + optional Type type = 5; + + // For message and enum types, this is the name of the type. If the name + // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping + // rules are used to find the type (i.e. first the nested types within this + // message are searched, then within the parent, on up to the root + // namespace). + optional string type_name = 6; + + // For extensions, this is the name of the type being extended. It is + // resolved in the same manner as type_name. + optional string extendee = 2; + + // For numeric types, contains the original text representation of the value. + // For booleans, "true" or "false". + // For strings, contains the default text contents (not escaped in any way). + // For bytes, contains the C escaped value. All bytes >= 128 are escaped. + optional string default_value = 7; + + // If set, gives the index of a oneof in the containing type's oneof_decl + // list. This field is a member of that oneof. + optional int32 oneof_index = 9; + + // JSON name of this field. The value is set by protocol compiler. If the + // user has set a "json_name" option on this field, that option's value + // will be used. Otherwise, it's deduced from the field's name by converting + // it to camelCase. + optional string json_name = 10; + + optional FieldOptions options = 8; + + // If true, this is a proto3 "optional". When a proto3 field is optional, it + // tracks presence regardless of field type. + // + // When proto3_optional is true, this field must belong to a oneof to signal + // to old proto3 clients that presence is tracked for this field. This oneof + // is known as a "synthetic" oneof, and this field must be its sole member + // (each proto3 optional field gets its own synthetic oneof). Synthetic oneofs + // exist in the descriptor only, and do not generate any API. Synthetic oneofs + // must be ordered after all "real" oneofs. + // + // For message fields, proto3_optional doesn't create any semantic change, + // since non-repeated message fields always track presence. However it still + // indicates the semantic detail of whether the user wrote "optional" or not. + // This can be useful for round-tripping the .proto file. For consistency we + // give message fields a synthetic oneof also, even though it is not required + // to track presence. This is especially important because the parser can't + // tell if a field is a message or an enum, so it must always create a + // synthetic oneof. + // + // Proto2 optional fields do not set this flag, because they already indicate + // optional with `LABEL_OPTIONAL`. + optional bool proto3_optional = 17; +} + +// Describes a oneof. +message OneofDescriptorProto { + optional string name = 1; + optional OneofOptions options = 2; +} + +// Describes an enum type. +message EnumDescriptorProto { + optional string name = 1; + + repeated EnumValueDescriptorProto value = 2; + + optional EnumOptions options = 3; + + // Range of reserved numeric values. Reserved values may not be used by + // entries in the same enum. Reserved ranges may not overlap. + // + // Note that this is distinct from DescriptorProto.ReservedRange in that it + // is inclusive such that it can appropriately represent the entire int32 + // domain. + message EnumReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Inclusive. + } + + // Range of reserved numeric values. Reserved numeric values may not be used + // by enum values in the same enum declaration. Reserved ranges may not + // overlap. + repeated EnumReservedRange reserved_range = 4; + + // Reserved enum value names, which may not be reused. A given name may only + // be reserved once. + repeated string reserved_name = 5; + + // Support for `export` and `local` keywords on enums. + optional SymbolVisibility visibility = 6; +} + +// Describes a value within an enum. +message EnumValueDescriptorProto { + optional string name = 1; + optional int32 number = 2; + + optional EnumValueOptions options = 3; +} + +// Describes a service. +message ServiceDescriptorProto { + optional string name = 1; + repeated MethodDescriptorProto method = 2; + + optional ServiceOptions options = 3; + + reserved 4; + reserved "stream"; +} + +// Describes a method of a service. +message MethodDescriptorProto { + optional string name = 1; + + // Input and output type names. These are resolved in the same way as + // FieldDescriptorProto.type_name, but must refer to a message type. + optional string input_type = 2; + optional string output_type = 3; + + optional MethodOptions options = 4; + + // Identifies if client streams multiple client messages + optional bool client_streaming = 5 [default = false]; + // Identifies if server streams multiple server messages + optional bool server_streaming = 6 [default = false]; +} + +// =================================================================== +// Options + +// Each of the definitions above may have "options" attached. These are +// just annotations which may cause code to be generated slightly differently +// or may contain hints for code that manipulates protocol messages. +// +// Clients may define custom options as extensions of the *Options messages. +// These extensions may not yet be known at parsing time, so the parser cannot +// store the values in them. Instead it stores them in a field in the *Options +// message called uninterpreted_option. This field must have the same name +// across all *Options messages. We then use this field to populate the +// extensions when we build a descriptor, at which point all protos have been +// parsed and so all extensions are known. +// +// Extension numbers for custom options may be chosen as follows: +// * For options which will only be used within a single application or +// organization, or for experimental options, use field numbers 50000 +// through 99999. It is up to you to ensure that you do not use the +// same number for multiple options. +// * For options which will be published and used publicly by multiple +// independent entities, e-mail protobuf-global-extension-registry@google.com +// to reserve extension numbers. Simply provide your project name (e.g. +// Objective-C plugin) and your project website (if available) -- there's no +// need to explain how you intend to use them. Usually you only need one +// extension number. You can declare multiple options with only one extension +// number by putting them in a sub-message. See the Custom Options section of +// the docs for examples: +// https://developers.google.com/protocol-buffers/docs/proto#options +// If this turns out to be popular, a web service will be set up +// to automatically assign option numbers. + +message FileOptions { + + // Sets the Java package where classes generated from this .proto will be + // placed. By default, the proto package is used, but this is often + // inappropriate because proto packages do not normally start with backwards + // domain names. + optional string java_package = 1; + + // Controls the name of the wrapper Java class generated for the .proto file. + // That class will always contain the .proto file's getDescriptor() method as + // well as any top-level extensions defined in the .proto file. + // If java_multiple_files is disabled, then all the other classes from the + // .proto file will be nested inside the single wrapper outer class. + optional string java_outer_classname = 8; + + // If enabled, then the Java code generator will generate a separate .java + // file for each top-level message, enum, and service defined in the .proto + // file. Thus, these types will *not* be nested inside the wrapper class + // named by java_outer_classname. However, the wrapper class will still be + // generated to contain the file's getDescriptor() method as well as any + // top-level extensions defined in the file. + optional bool java_multiple_files = 10 [ + default = false, + feature_support = { + edition_introduced: EDITION_PROTO2 + edition_removed: EDITION_2024 + removal_error: "This behavior is enabled by default in editions 2024 and above. " + "To disable it, you can set `features.(pb.java).nest_in_file_class = YES` " + "on individual messages, enums, or services." + + } + ]; + + // This option does nothing. + optional bool java_generate_equals_and_hash = 20 [deprecated=true]; + + // A proto2 file can set this to true to opt in to UTF-8 checking for Java, + // which will throw an exception if invalid UTF-8 is parsed from the wire or + // assigned to a string field. + // + // TODO: clarify exactly what kinds of field types this option + // applies to, and update these docs accordingly. + // + // Proto3 files already perform these checks. Setting the option explicitly to + // false has no effect: it cannot be used to opt proto3 files out of UTF-8 + // checks. + optional bool java_string_check_utf8 = 27 [default = false]; + + // Generated classes can be optimized for speed or code size. + enum OptimizeMode { + SPEED = 1; // Generate complete code for parsing, serialization, + // etc. + CODE_SIZE = 2; // Use ReflectionOps to implement these methods. + LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. + } + optional OptimizeMode optimize_for = 9 [default = SPEED]; + + // Sets the Go package where structs generated from this .proto will be + // placed. If omitted, the Go package will be derived from the following: + // - The basename of the package import path, if provided. + // - Otherwise, the package statement in the .proto file, if present. + // - Otherwise, the basename of the .proto file, without extension. + optional string go_package = 11; + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of google.protobuf. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. Therefore, + // these default to false. Old code which depends on generic services should + // explicitly set them to true. + optional bool cc_generic_services = 16 [default = false]; + optional bool java_generic_services = 17 [default = false]; + optional bool py_generic_services = 18 [default = false]; + reserved 42; // removed php_generic_services + reserved "php_generic_services"; + + // Is this file deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for everything in the file, or it will be completely ignored; in the very + // least, this is a formalization for deprecating files. + optional bool deprecated = 23 [default = false]; + + // Enables the use of arenas for the proto messages in this file. This applies + // only to generated classes for C++. + optional bool cc_enable_arenas = 31 [default = true]; + + // Sets the objective c class prefix which is prepended to all objective c + // generated classes from this .proto. There is no default. + optional string objc_class_prefix = 36; + + // Namespace for generated classes; defaults to the package. + optional string csharp_namespace = 37; + + // By default Swift generators will take the proto package and CamelCase it + // replacing '.' with underscore and use that to prefix the types/symbols + // defined. When this options is provided, they will use this value instead + // to prefix the types/symbols defined. + optional string swift_prefix = 39; + + // Sets the php class prefix which is prepended to all php generated classes + // from this .proto. Default is empty. + optional string php_class_prefix = 40; + + // Use this option to change the namespace of php generated classes. Default + // is empty. When this option is empty, the package name will be used for + // determining the namespace. + optional string php_namespace = 41; + + // Use this option to change the namespace of php generated metadata classes. + // Default is empty. When this option is empty, the proto file name will be + // used for determining the namespace. + optional string php_metadata_namespace = 44; + + // Use this option to change the package of ruby generated classes. Default + // is empty. When this option is not set, the package name will be used for + // determining the ruby package. + optional string ruby_package = 45; + + // Any features defined in the specific edition. + // WARNING: This field should only be used by protobuf plugins or special + // cases like the proto compiler. Other uses are discouraged and + // developers should rely on the protoreflect APIs for their client language. + optional FeatureSet features = 50; + + // The parser stores options it doesn't recognize here. + // See the documentation for the "Options" section above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. + // See the documentation for the "Options" section above. + extensions 1000 to max; + + reserved 38; +} + +message MessageOptions { + // Set true to use the old proto1 MessageSet wire format for extensions. + // This is provided for backwards-compatibility with the MessageSet wire + // format. You should not use this for any other reason: It's less + // efficient, has fewer features, and is more complicated. + // + // The message must be defined exactly as follows: + // message Foo { + // option message_set_wire_format = true; + // extensions 4 to max; + // } + // Note that the message cannot have any defined fields; MessageSets only + // have extensions. + // + // All extensions of your type must be singular messages; e.g. they cannot + // be int32s, enums, or repeated messages. + // + // Because this is an option, the above two restrictions are not enforced by + // the protocol compiler. + optional bool message_set_wire_format = 1 [default = false]; + + // Disables the generation of the standard "descriptor()" accessor, which can + // conflict with a field of the same name. This is meant to make migration + // from proto1 easier; new code should avoid fields named "descriptor". + optional bool no_standard_descriptor_accessor = 2 [default = false]; + + // Is this message deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the message, or it will be completely ignored; in the very least, + // this is a formalization for deprecating messages. + optional bool deprecated = 3 [default = false]; + + reserved 4, 5, 6; + + // Whether the message is an automatically generated map entry type for the + // maps field. + // + // For maps fields: + // map map_field = 1; + // The parsed descriptor looks like: + // message MapFieldEntry { + // option map_entry = true; + // optional KeyType key = 1; + // optional ValueType value = 2; + // } + // repeated MapFieldEntry map_field = 1; + // + // Implementations may choose not to generate the map_entry=true message, but + // use a native map in the target language to hold the keys and values. + // The reflection APIs in such implementations still need to work as + // if the field is a repeated message field. + // + // NOTE: Do not set the option in .proto files. Always use the maps syntax + // instead. The option should only be implicitly set by the proto compiler + // parser. + optional bool map_entry = 7; + + reserved 8; // javalite_serializable + reserved 9; // javanano_as_lite + + // Enable the legacy handling of JSON field name conflicts. This lowercases + // and strips underscored from the fields before comparison in proto3 only. + // The new behavior takes `json_name` into account and applies to proto2 as + // well. + // + // This should only be used as a temporary measure against broken builds due + // to the change in behavior for JSON field name conflicts. + // + // TODO This is legacy behavior we plan to remove once downstream + // teams have had time to migrate. + optional bool deprecated_legacy_json_field_conflicts = 11 [deprecated = true]; + + // Any features defined in the specific edition. + // WARNING: This field should only be used by protobuf plugins or special + // cases like the proto compiler. Other uses are discouraged and + // developers should rely on the protoreflect APIs for their client language. + optional FeatureSet features = 12; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message FieldOptions { + // NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead. + // The ctype option instructs the C++ code generator to use a different + // representation of the field than it normally would. See the specific + // options below. This option is only implemented to support use of + // [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of + // type "bytes" in the open source release. + // TODO: make ctype actually deprecated. + optional CType ctype = 1 [/*deprecated = true,*/ default = STRING]; + enum CType { + // Default mode. + STRING = 0; + + // The option [ctype=CORD] may be applied to a non-repeated field of type + // "bytes". It indicates that in C++, the data should be stored in a Cord + // instead of a string. For very large strings, this may reduce memory + // fragmentation. It may also allow better performance when parsing from a + // Cord, or when parsing with aliasing enabled, as the parsed Cord may then + // alias the original buffer. + CORD = 1; + + STRING_PIECE = 2; + } + // The packed option can be enabled for repeated primitive fields to enable + // a more efficient representation on the wire. Rather than repeatedly + // writing the tag and type for each element, the entire array is encoded as + // a single length-delimited blob. In proto3, only explicit setting it to + // false will avoid using packed encoding. This option is prohibited in + // Editions, but the `repeated_field_encoding` feature can be used to control + // the behavior. + optional bool packed = 2; + + // The jstype option determines the JavaScript type used for values of the + // field. The option is permitted only for 64 bit integral and fixed types + // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING + // is represented as JavaScript string, which avoids loss of precision that + // can happen when a large value is converted to a floating point JavaScript. + // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to + // use the JavaScript "number" type. The behavior of the default option + // JS_NORMAL is implementation dependent. + // + // This option is an enum to permit additional types to be added, e.g. + // goog.math.Integer. + optional JSType jstype = 6 [default = JS_NORMAL]; + enum JSType { + // Use the default type. + JS_NORMAL = 0; + + // Use JavaScript strings. + JS_STRING = 1; + + // Use JavaScript numbers. + JS_NUMBER = 2; + } + + // Should this field be parsed lazily? Lazy applies only to message-type + // fields. It means that when the outer message is initially parsed, the + // inner message's contents will not be parsed but instead stored in encoded + // form. The inner message will actually be parsed when it is first accessed. + // + // This is only a hint. Implementations are free to choose whether to use + // eager or lazy parsing regardless of the value of this option. However, + // setting this option true suggests that the protocol author believes that + // using lazy parsing on this field is worth the additional bookkeeping + // overhead typically needed to implement it. + // + // This option does not affect the public interface of any generated code; + // all method signatures remain the same. Furthermore, thread-safety of the + // interface is not affected by this option; const methods remain safe to + // call from multiple threads concurrently, while non-const methods continue + // to require exclusive access. + // + // Note that lazy message fields are still eagerly verified to check + // ill-formed wireformat or missing required fields. Calling IsInitialized() + // on the outer message would fail if the inner message has missing required + // fields. Failed verification would result in parsing failure (except when + // uninitialized messages are acceptable). + optional bool lazy = 5 [default = false]; + + // unverified_lazy does no correctness checks on the byte stream. This should + // only be used where lazy with verification is prohibitive for performance + // reasons. + optional bool unverified_lazy = 15 [default = false]; + + // Is this field deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for accessors, or it will be completely ignored; in the very least, this + // is a formalization for deprecating fields. + optional bool deprecated = 3 [default = false]; + + // DEPRECATED. DO NOT USE! + // For Google-internal migration only. Do not use. + optional bool weak = 10 [default = false, deprecated = true]; + + // Indicate that the field value should not be printed out when using debug + // formats, e.g. when the field contains sensitive credentials. + optional bool debug_redact = 16 [default = false]; + + // If set to RETENTION_SOURCE, the option will be omitted from the binary. + enum OptionRetention { + RETENTION_UNKNOWN = 0; + RETENTION_RUNTIME = 1; + RETENTION_SOURCE = 2; + } + + optional OptionRetention retention = 17; + + // This indicates the types of entities that the field may apply to when used + // as an option. If it is unset, then the field may be freely used as an + // option on any kind of entity. + enum OptionTargetType { + TARGET_TYPE_UNKNOWN = 0; + TARGET_TYPE_FILE = 1; + TARGET_TYPE_EXTENSION_RANGE = 2; + TARGET_TYPE_MESSAGE = 3; + TARGET_TYPE_FIELD = 4; + TARGET_TYPE_ONEOF = 5; + TARGET_TYPE_ENUM = 6; + TARGET_TYPE_ENUM_ENTRY = 7; + TARGET_TYPE_SERVICE = 8; + TARGET_TYPE_METHOD = 9; + } + + repeated OptionTargetType targets = 19; + + message EditionDefault { + optional Edition edition = 3; + optional string value = 2; // Textproto value. + } + repeated EditionDefault edition_defaults = 20; + + // Any features defined in the specific edition. + // WARNING: This field should only be used by protobuf plugins or special + // cases like the proto compiler. Other uses are discouraged and + // developers should rely on the protoreflect APIs for their client language. + optional FeatureSet features = 21; + + // Information about the support window of a feature. + message FeatureSupport { + // The edition that this feature was first available in. In editions + // earlier than this one, the default assigned to EDITION_LEGACY will be + // used, and proto files will not be able to override it. + optional Edition edition_introduced = 1; + + // The edition this feature becomes deprecated in. Using this after this + // edition may trigger warnings. + optional Edition edition_deprecated = 2; + + // The deprecation warning text if this feature is used after the edition it + // was marked deprecated in. + optional string deprecation_warning = 3; + + // The edition this feature is no longer available in. In editions after + // this one, the last default assigned will be used, and proto files will + // not be able to override it. + optional Edition edition_removed = 4; + + // The removal error text if this feature is used after the edition it was + // removed in. + optional string removal_error = 5; + } + optional FeatureSupport feature_support = 22; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; + + reserved 4; // removed jtype + reserved 18; // reserve target, target_obsolete_do_not_use +} + +message OneofOptions { + // Any features defined in the specific edition. + // WARNING: This field should only be used by protobuf plugins or special + // cases like the proto compiler. Other uses are discouraged and + // developers should rely on the protoreflect APIs for their client language. + optional FeatureSet features = 1; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumOptions { + + // Set this option to true to allow mapping different tag names to the same + // value. + optional bool allow_alias = 2; + + // Is this enum deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum, or it will be completely ignored; in the very least, this + // is a formalization for deprecating enums. + optional bool deprecated = 3 [default = false]; + + reserved 5; // javanano_as_lite + + // Enable the legacy handling of JSON field name conflicts. This lowercases + // and strips underscored from the fields before comparison in proto3 only. + // The new behavior takes `json_name` into account and applies to proto2 as + // well. + // TODO Remove this legacy behavior once downstream teams have + // had time to migrate. + optional bool deprecated_legacy_json_field_conflicts = 6 [deprecated = true]; + + // Any features defined in the specific edition. + // WARNING: This field should only be used by protobuf plugins or special + // cases like the proto compiler. Other uses are discouraged and + // developers should rely on the protoreflect APIs for their client language. + optional FeatureSet features = 7; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumValueOptions { + // Is this enum value deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum value, or it will be completely ignored; in the very least, + // this is a formalization for deprecating enum values. + optional bool deprecated = 1 [default = false]; + + // Any features defined in the specific edition. + // WARNING: This field should only be used by protobuf plugins or special + // cases like the proto compiler. Other uses are discouraged and + // developers should rely on the protoreflect APIs for their client language. + optional FeatureSet features = 2; + + // Indicate that fields annotated with this enum value should not be printed + // out when using debug formats, e.g. when the field contains sensitive + // credentials. + optional bool debug_redact = 3 [default = false]; + + // Information about the support window of a feature value. + optional FieldOptions.FeatureSupport feature_support = 4; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message ServiceOptions { + + // Any features defined in the specific edition. + // WARNING: This field should only be used by protobuf plugins or special + // cases like the proto compiler. Other uses are discouraged and + // developers should rely on the protoreflect APIs for their client language. + optional FeatureSet features = 34; + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this service deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the service, or it will be completely ignored; in the very least, + // this is a formalization for deprecating services. + optional bool deprecated = 33 [default = false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MethodOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this method deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the method, or it will be completely ignored; in the very least, + // this is a formalization for deprecating methods. + optional bool deprecated = 33 [default = false]; + + // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, + // or neither? HTTP based RPC implementation may choose GET verb for safe + // methods, and PUT verb for idempotent methods instead of the default POST. + enum IdempotencyLevel { + IDEMPOTENCY_UNKNOWN = 0; + NO_SIDE_EFFECTS = 1; // implies idempotent + IDEMPOTENT = 2; // idempotent, but may have side effects + } + optional IdempotencyLevel idempotency_level = 34 + [default = IDEMPOTENCY_UNKNOWN]; + + // Any features defined in the specific edition. + // WARNING: This field should only be used by protobuf plugins or special + // cases like the proto compiler. Other uses are discouraged and + // developers should rely on the protoreflect APIs for their client language. + optional FeatureSet features = 35; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +// A message representing a option the parser does not recognize. This only +// appears in options protos created by the compiler::Parser class. +// DescriptorPool resolves these when building Descriptor objects. Therefore, +// options protos in descriptor objects (e.g. returned by Descriptor::options(), +// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions +// in them. +message UninterpretedOption { + // The name of the uninterpreted option. Each string represents a segment in + // a dot-separated name. is_extension is true iff a segment represents an + // extension (denoted with parentheses in options specs in .proto files). + // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents + // "foo.(bar.baz).moo". + message NamePart { + required string name_part = 1; + required bool is_extension = 2; + } + repeated NamePart name = 2; + + // The value of the uninterpreted option, in whatever type the tokenizer + // identified it as during parsing. Exactly one of these should be set. + optional string identifier_value = 3; + optional uint64 positive_int_value = 4; + optional int64 negative_int_value = 5; + optional double double_value = 6; + optional bytes string_value = 7; + optional string aggregate_value = 8; +} + +// =================================================================== +// Features + +// TODO Enums in C++ gencode (and potentially other languages) are +// not well scoped. This means that each of the feature enums below can clash +// with each other. The short names we've chosen maximize call-site +// readability, but leave us very open to this scenario. A future feature will +// be designed and implemented to handle this, hopefully before we ever hit a +// conflict here. +message FeatureSet { + enum FieldPresence { + FIELD_PRESENCE_UNKNOWN = 0; + EXPLICIT = 1; + IMPLICIT = 2; + LEGACY_REQUIRED = 3; + } + optional FieldPresence field_presence = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "EXPLICIT" }, + edition_defaults = { edition: EDITION_PROTO3, value: "IMPLICIT" }, + edition_defaults = { edition: EDITION_2023, value: "EXPLICIT" } + ]; + + enum EnumType { + ENUM_TYPE_UNKNOWN = 0; + OPEN = 1; + CLOSED = 2; + } + optional EnumType enum_type = 2 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "CLOSED" }, + edition_defaults = { edition: EDITION_PROTO3, value: "OPEN" } + ]; + + enum RepeatedFieldEncoding { + REPEATED_FIELD_ENCODING_UNKNOWN = 0; + PACKED = 1; + EXPANDED = 2; + } + optional RepeatedFieldEncoding repeated_field_encoding = 3 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "EXPANDED" }, + edition_defaults = { edition: EDITION_PROTO3, value: "PACKED" } + ]; + + enum Utf8Validation { + UTF8_VALIDATION_UNKNOWN = 0; + VERIFY = 2; + NONE = 3; + reserved 1; + } + optional Utf8Validation utf8_validation = 4 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "NONE" }, + edition_defaults = { edition: EDITION_PROTO3, value: "VERIFY" } + ]; + + enum MessageEncoding { + MESSAGE_ENCODING_UNKNOWN = 0; + LENGTH_PREFIXED = 1; + DELIMITED = 2; + } + optional MessageEncoding message_encoding = 5 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "LENGTH_PREFIXED" } + ]; + + enum JsonFormat { + JSON_FORMAT_UNKNOWN = 0; + ALLOW = 1; + LEGACY_BEST_EFFORT = 2; + } + optional JsonFormat json_format = 6 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "LEGACY_BEST_EFFORT" }, + edition_defaults = { edition: EDITION_PROTO3, value: "ALLOW" } + ]; + + enum EnforceNamingStyle { + ENFORCE_NAMING_STYLE_UNKNOWN = 0; + STYLE2024 = 1; + STYLE_LEGACY = 2; + } + optional EnforceNamingStyle enforce_naming_style = 7 [ + retention = RETENTION_SOURCE, + targets = TARGET_TYPE_FILE, + targets = TARGET_TYPE_EXTENSION_RANGE, + targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_ONEOF, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_ENUM_ENTRY, + targets = TARGET_TYPE_SERVICE, + targets = TARGET_TYPE_METHOD, + feature_support = { + edition_introduced: EDITION_2024, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "STYLE_LEGACY" }, + edition_defaults = { edition: EDITION_2024, value: "STYLE2024" } + ]; + + message VisibilityFeature { + enum DefaultSymbolVisibility { + DEFAULT_SYMBOL_VISIBILITY_UNKNOWN = 0; + + // Default pre-EDITION_2024, all UNSET visibility are export. + EXPORT_ALL = 1; + + // All top-level symbols default to export, nested default to local. + EXPORT_TOP_LEVEL = 2; + + // All symbols default to local. + LOCAL_ALL = 3; + + // All symbols local by default. Nested types cannot be exported. + // With special case caveat for message { enum {} reserved 1 to max; } + // This is the recommended setting for new protos. + STRICT = 4; + } + reserved 1 to max; + } + optional VisibilityFeature.DefaultSymbolVisibility default_symbol_visibility = + 8 [ + retention = RETENTION_SOURCE, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2024, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "EXPORT_ALL" }, + edition_defaults = { edition: EDITION_2024, value: "EXPORT_TOP_LEVEL" } + ]; + + reserved 999; + + extensions 1000 to 9994 [ + declaration = { + number: 1000, + full_name: ".pb.cpp", + type: ".pb.CppFeatures" + }, + declaration = { + number: 1001, + full_name: ".pb.java", + type: ".pb.JavaFeatures" + }, + declaration = { number: 1002, full_name: ".pb.go", type: ".pb.GoFeatures" }, + declaration = { + number: 1003, + full_name: ".pb.python", + type: ".pb.PythonFeatures" + }, + declaration = { + number: 1100, + full_name: ".imp.impress_feature_set", + type: ".imp.ImpressFeatureSet" + }, + declaration = { + number: 9989, + full_name: ".pb.java_mutable", + type: ".pb.JavaMutableFeatures" + }, + declaration = { + number: 9990, + full_name: ".pb.proto1", + type: ".pb.Proto1Features" + } + ]; + + extensions 9995 to 9999; // For internal testing + extensions 10000; // for https://github.com/bufbuild/protobuf-es +} + +// A compiled specification for the defaults of a set of features. These +// messages are generated from FeatureSet extensions and can be used to seed +// feature resolution. The resolution with this object becomes a simple search +// for the closest matching edition, followed by proto merges. +message FeatureSetDefaults { + // A map from every known edition with a unique set of defaults to its + // defaults. Not all editions may be contained here. For a given edition, + // the defaults at the closest matching edition ordered at or before it should + // be used. This field must be in strict ascending order by edition. + message FeatureSetEditionDefault { + optional Edition edition = 3; + + // Defaults of features that can be overridden in this edition. + optional FeatureSet overridable_features = 4; + + // Defaults of features that can't be overridden in this edition. + optional FeatureSet fixed_features = 5; + + reserved 1, 2; + reserved "features"; + } + repeated FeatureSetEditionDefault defaults = 1; + + // The minimum supported edition (inclusive) when this was constructed. + // Editions before this will not have defaults. + optional Edition minimum_edition = 4; + + // The maximum known edition (inclusive) when this was constructed. Editions + // after this will not have reliable defaults. + optional Edition maximum_edition = 5; +} + +// =================================================================== +// Optional source code info + +// Encapsulates information about the original source file from which a +// FileDescriptorProto was generated. +message SourceCodeInfo { + // A Location identifies a piece of source code in a .proto file which + // corresponds to a particular definition. This information is intended + // to be useful to IDEs, code indexers, documentation generators, and similar + // tools. + // + // For example, say we have a file like: + // message Foo { + // optional string foo = 1; + // } + // Let's look at just the field definition: + // optional string foo = 1; + // ^ ^^ ^^ ^ ^^^ + // a bc de f ghi + // We have the following locations: + // span path represents + // [a,i) [ 4, 0, 2, 0 ] The whole field definition. + // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + // + // Notes: + // - A location may refer to a repeated field itself (i.e. not to any + // particular index within it). This is used whenever a set of elements are + // logically enclosed in a single code segment. For example, an entire + // extend block (possibly containing multiple extension definitions) will + // have an outer location whose path refers to the "extensions" repeated + // field without an index. + // - Multiple locations may have the same path. This happens when a single + // logical declaration is spread out across multiple places. The most + // obvious example is the "extend" block again -- there may be multiple + // extend blocks in the same scope, each of which will have the same path. + // - A location's span is not always a subset of its parent's span. For + // example, the "extendee" of an extension declaration appears at the + // beginning of the "extend" block and is shared by all extensions within + // the block. + // - Just because a location's span is a subset of some other location's span + // does not mean that it is a descendant. For example, a "group" defines + // both a type and a field in a single declaration. Thus, the locations + // corresponding to the type and field and their components will overlap. + // - Code which tries to interpret locations should probably be designed to + // ignore those that it doesn't understand, as more types of locations could + // be recorded in the future. + repeated Location location = 1; + message Location { + // Identifies which part of the FileDescriptorProto was defined at this + // location. + // + // Each element is a field number or an index. They form a path from + // the root FileDescriptorProto to the place where the definition appears. + // For example, this path: + // [ 4, 3, 2, 7, 1 ] + // refers to: + // file.message_type(3) // 4, 3 + // .field(7) // 2, 7 + // .name() // 1 + // This is because FileDescriptorProto.message_type has field number 4: + // repeated DescriptorProto message_type = 4; + // and DescriptorProto.field has field number 2: + // repeated FieldDescriptorProto field = 2; + // and FieldDescriptorProto.name has field number 1: + // optional string name = 1; + // + // Thus, the above path gives the location of a field name. If we removed + // the last element: + // [ 4, 3, 2, 7 ] + // this path refers to the whole field declaration (from the beginning + // of the label to the terminating semicolon). + repeated int32 path = 1 [packed = true]; + + // Always has exactly three or four elements: start line, start column, + // end line (optional, otherwise assumed same as start line), end column. + // These are packed into a single field for efficiency. Note that line + // and column numbers are zero-based -- typically you will want to add + // 1 to each before displaying to a user. + repeated int32 span = 2 [packed = true]; + + // If this SourceCodeInfo represents a complete declaration, these are any + // comments appearing before and after the declaration which appear to be + // attached to the declaration. + // + // A series of line comments appearing on consecutive lines, with no other + // tokens appearing on those lines, will be treated as a single comment. + // + // leading_detached_comments will keep paragraphs of comments that appear + // before (but not connected to) the current element. Each paragraph, + // separated by empty lines, will be one comment element in the repeated + // field. + // + // Only the comment content is provided; comment markers (e.g. //) are + // stripped out. For block comments, leading whitespace and an asterisk + // will be stripped from the beginning of each line other than the first. + // Newlines are included in the output. + // + // Examples: + // + // optional int32 foo = 1; // Comment attached to foo. + // // Comment attached to bar. + // optional int32 bar = 2; + // + // optional string baz = 3; + // // Comment attached to baz. + // // Another line attached to baz. + // + // // Comment attached to moo. + // // + // // Another line attached to moo. + // optional double moo = 4; + // + // // Detached comment for corge. This is not leading or trailing comments + // // to moo or corge because there are blank lines separating it from + // // both. + // + // // Detached comment for corge paragraph 2. + // + // optional string corge = 5; + // /* Block comment attached + // * to corge. Leading asterisks + // * will be removed. */ + // /* Block comment attached to + // * grault. */ + // optional int32 grault = 6; + // + // // ignored detached comments. + optional string leading_comments = 3; + optional string trailing_comments = 4; + repeated string leading_detached_comments = 6; + } + + // Extensions for tooling. + extensions 536000000 [declaration = { + number: 536000000 + type: ".buf.descriptor.v1.SourceCodeInfoExtension" + full_name: ".buf.descriptor.v1.buf_source_code_info_extension" + }]; +} + +// Describes the relationship between generated code and its original source +// file. A GeneratedCodeInfo message is associated with only one generated +// source file, but may contain references to different source .proto files. +message GeneratedCodeInfo { + // An Annotation connects some span of text in generated code to an element + // of its generating .proto file. + repeated Annotation annotation = 1; + message Annotation { + // Identifies the element in the original source .proto file. This field + // is formatted the same as SourceCodeInfo.Location.path. + repeated int32 path = 1 [packed = true]; + + // Identifies the filesystem path to the original source .proto. + optional string source_file = 2; + + // Identifies the starting offset in bytes in the generated code + // that relates to the identified object. + optional int32 begin = 3; + + // Identifies the ending offset in bytes in the generated code that + // relates to the identified object. The end offset should be one past + // the last relevant byte (so the length of the text = end - begin). + optional int32 end = 4; + + // Represents the identified object's effect on the element in the original + // .proto file. + enum Semantic { + // There is no effect or the effect is indescribable. + NONE = 0; + // The element is set or otherwise mutated. + SET = 1; + // An alias to the element is returned. + ALIAS = 2; + } + optional Semantic semantic = 5; + } +} + +// Describes the 'visibility' of a symbol with respect to the proto import +// system. Symbols can only be imported when the visibility rules do not prevent +// it (ex: local symbols cannot be imported). Visibility modifiers can only set +// on `message` and `enum` as they are the only types available to be referenced +// from other files. +enum SymbolVisibility { + VISIBILITY_UNSET = 0; + VISIBILITY_LOCAL = 1; + VISIBILITY_EXPORT = 2; +} diff --git a/flow/proto/google/protobuf/duration.proto b/flow/proto/google/protobuf/duration.proto new file mode 100644 index 00000000000..41f40c22247 --- /dev/null +++ b/flow/proto/google/protobuf/duration.proto @@ -0,0 +1,115 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/durationpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DurationProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; + +// A Duration represents a signed, fixed-length span of time represented +// as a count of seconds and fractions of seconds at nanosecond +// resolution. It is independent of any calendar and concepts like "day" +// or "month". It is related to Timestamp in that the difference between +// two Timestamp values is a Duration and it can be added or subtracted +// from a Timestamp. Range is approximately +-10,000 years. +// +// # Examples +// +// Example 1: Compute Duration from two Timestamps in pseudo code. +// +// Timestamp start = ...; +// Timestamp end = ...; +// Duration duration = ...; +// +// duration.seconds = end.seconds - start.seconds; +// duration.nanos = end.nanos - start.nanos; +// +// if (duration.seconds < 0 && duration.nanos > 0) { +// duration.seconds += 1; +// duration.nanos -= 1000000000; +// } else if (duration.seconds > 0 && duration.nanos < 0) { +// duration.seconds -= 1; +// duration.nanos += 1000000000; +// } +// +// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +// +// Timestamp start = ...; +// Duration duration = ...; +// Timestamp end = ...; +// +// end.seconds = start.seconds + duration.seconds; +// end.nanos = start.nanos + duration.nanos; +// +// if (end.nanos < 0) { +// end.seconds -= 1; +// end.nanos += 1000000000; +// } else if (end.nanos >= 1000000000) { +// end.seconds += 1; +// end.nanos -= 1000000000; +// } +// +// Example 3: Compute Duration from datetime.timedelta in Python. +// +// td = datetime.timedelta(days=3, minutes=10) +// duration = Duration() +// duration.FromTimedelta(td) +// +// # JSON Mapping +// +// In JSON format, the Duration type is encoded as a string rather than an +// object, where the string ends in the suffix "s" (indicating seconds) and +// is preceded by the number of seconds, with nanoseconds expressed as +// fractional seconds. For example, 3 seconds with 0 nanoseconds should be +// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should +// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 +// microsecond should be expressed in JSON format as "3.000001s". +// +message Duration { + // Signed seconds of the span of time. Must be from -315,576,000,000 + // to +315,576,000,000 inclusive. Note: these bounds are computed from: + // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + int64 seconds = 1; + + // Signed fractions of a second at nanosecond resolution of the span + // of time. Durations less than one second are represented with a 0 + // `seconds` field and a positive or negative `nanos` field. For durations + // of one second or more, a non-zero value for the `nanos` field must be + // of the same sign as the `seconds` field. Must be from -999,999,999 + // to +999,999,999 inclusive. + int32 nanos = 2; +} diff --git a/flow/proto/google/protobuf/empty.proto b/flow/proto/google/protobuf/empty.proto new file mode 100644 index 00000000000..b87c89dcfce --- /dev/null +++ b/flow/proto/google/protobuf/empty.proto @@ -0,0 +1,51 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option go_package = "google.golang.org/protobuf/types/known/emptypb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "EmptyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option cc_enable_arenas = true; + +// A generic empty message that you can re-use to avoid defining duplicated +// empty messages in your APIs. A typical example is to use it as the request +// or the response type of an API method. For instance: +// +// service Foo { +// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); +// } +// +message Empty {} diff --git a/flow/proto/google/protobuf/field_mask.proto b/flow/proto/google/protobuf/field_mask.proto new file mode 100644 index 00000000000..7093fba50dd --- /dev/null +++ b/flow/proto/google/protobuf/field_mask.proto @@ -0,0 +1,243 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "FieldMaskProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; +option cc_enable_arenas = true; + +// `FieldMask` represents a set of symbolic field paths, for example: +// +// paths: "f.a" +// paths: "f.b.d" +// +// Here `f` represents a field in some root message, `a` and `b` +// fields in the message found in `f`, and `d` a field found in the +// message in `f.b`. +// +// Field masks are used to specify a subset of fields that should be +// returned by a get operation or modified by an update operation. +// Field masks also have a custom JSON encoding (see below). +// +// # Field Masks in Projections +// +// When used in the context of a projection, a response message or +// sub-message is filtered by the API to only contain those fields as +// specified in the mask. For example, if the mask in the previous +// example is applied to a response message as follows: +// +// f { +// a : 22 +// b { +// d : 1 +// x : 2 +// } +// y : 13 +// } +// z: 8 +// +// The result will not contain specific values for fields x,y and z +// (their value will be set to the default, and omitted in proto text +// output): +// +// +// f { +// a : 22 +// b { +// d : 1 +// } +// } +// +// A repeated field is not allowed except at the last position of a +// paths string. +// +// If a FieldMask object is not present in a get operation, the +// operation applies to all fields (as if a FieldMask of all fields +// had been specified). +// +// Note that a field mask does not necessarily apply to the +// top-level response message. In case of a REST get operation, the +// field mask applies directly to the response, but in case of a REST +// list operation, the mask instead applies to each individual message +// in the returned resource list. In case of a REST custom method, +// other definitions may be used. Where the mask applies will be +// clearly documented together with its declaration in the API. In +// any case, the effect on the returned resource/resources is required +// behavior for APIs. +// +// # Field Masks in Update Operations +// +// A field mask in update operations specifies which fields of the +// targeted resource are going to be updated. The API is required +// to only change the values of the fields as specified in the mask +// and leave the others untouched. If a resource is passed in to +// describe the updated values, the API ignores the values of all +// fields not covered by the mask. +// +// If a repeated field is specified for an update operation, new values will +// be appended to the existing repeated field in the target resource. Note that +// a repeated field is only allowed in the last position of a `paths` string. +// +// If a sub-message is specified in the last position of the field mask for an +// update operation, then new value will be merged into the existing sub-message +// in the target resource. +// +// For example, given the target message: +// +// f { +// b { +// d: 1 +// x: 2 +// } +// c: [1] +// } +// +// And an update message: +// +// f { +// b { +// d: 10 +// } +// c: [2] +// } +// +// then if the field mask is: +// +// paths: ["f.b", "f.c"] +// +// then the result will be: +// +// f { +// b { +// d: 10 +// x: 2 +// } +// c: [1, 2] +// } +// +// An implementation may provide options to override this default behavior for +// repeated and message fields. +// +// Note that libraries which implement FieldMask resolution have various +// different behaviors in the face of empty masks or the special "*" mask. +// When implementing a service you should confirm these cases have the +// appropriate behavior in the underlying FieldMask library that you desire, +// and you may need to special case those cases in your application code if +// the underlying field mask library behavior differs from your intended +// service semantics. +// +// Update methods implementing https://google.aip.dev/134 +// - MUST support the special value * meaning "full replace" +// - MUST treat an omitted field mask as "replace fields which are present". +// +// Other methods implementing https://google.aip.dev/157 +// - SHOULD support the special value "*" to mean "get all". +// - MUST treat an omitted field mask to mean "get all", unless otherwise +// documented. +// +// ## Considerations for HTTP REST +// +// The HTTP kind of an update operation which uses a field mask must +// be set to PATCH instead of PUT in order to satisfy HTTP semantics +// (PUT must only be used for full updates). +// +// # JSON Encoding of Field Masks +// +// In JSON, a field mask is encoded as a single string where paths are +// separated by a comma. Fields name in each path are converted +// to/from lower-camel naming conventions. +// +// As an example, consider the following message declarations: +// +// message Profile { +// User user = 1; +// Photo photo = 2; +// } +// message User { +// string display_name = 1; +// string address = 2; +// } +// +// In proto a field mask for `Profile` may look as such: +// +// mask { +// paths: "user.display_name" +// paths: "photo" +// } +// +// In JSON, the same mask is represented as below: +// +// { +// mask: "user.displayName,photo" +// } +// +// # Field Masks and Oneof Fields +// +// Field masks treat fields in oneofs just as regular fields. Consider the +// following message: +// +// message SampleMessage { +// oneof test_oneof { +// string name = 4; +// SubMessage sub_message = 9; +// } +// } +// +// The field mask can be: +// +// mask { +// paths: "name" +// } +// +// Or: +// +// mask { +// paths: "sub_message" +// } +// +// Note that oneof type names ("test_oneof" in this case) cannot be used in +// paths. +// +// ## Field Mask Verification +// +// The implementation of any API method which has a FieldMask type field in the +// request should verify the included field paths, and return an +// `INVALID_ARGUMENT` error if any path is unmappable. +message FieldMask { + // The set of field mask paths. + repeated string paths = 1; +} diff --git a/flow/proto/google/protobuf/go_features.proto b/flow/proto/google/protobuf/go_features.proto new file mode 100644 index 00000000000..13819acd3b4 --- /dev/null +++ b/flow/proto/google/protobuf/go_features.proto @@ -0,0 +1,112 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +syntax = "proto2"; + +package pb; + +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/protobuf/types/gofeaturespb"; + +extend google.protobuf.FeatureSet { + optional GoFeatures go = 1002; +} + +message GoFeatures { + // Whether or not to generate the deprecated UnmarshalJSON method for enums. + // Can only be true for proto using the Open Struct api. + optional bool legacy_unmarshal_json_enum = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + edition_deprecated: EDITION_2023, + deprecation_warning: "The legacy UnmarshalJSON API is deprecated and " + "will be removed in a future edition.", + }, + edition_defaults = { edition: EDITION_LEGACY, value: "true" }, + edition_defaults = { edition: EDITION_PROTO3, value: "false" } + ]; + + enum APILevel { + // API_LEVEL_UNSPECIFIED results in selecting the OPEN API, + // but needs to be a separate value to distinguish between + // an explicitly set api level or a missing api level. + API_LEVEL_UNSPECIFIED = 0; + API_OPEN = 1; + API_HYBRID = 2; + API_OPAQUE = 3; + } + + // One of OPEN, HYBRID or OPAQUE. + optional APILevel api_level = 2 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = { + edition: EDITION_LEGACY, + value: "API_LEVEL_UNSPECIFIED" + }, + edition_defaults = { edition: EDITION_2024, value: "API_OPAQUE" } + ]; + + enum StripEnumPrefix { + STRIP_ENUM_PREFIX_UNSPECIFIED = 0; + STRIP_ENUM_PREFIX_KEEP = 1; + STRIP_ENUM_PREFIX_GENERATE_BOTH = 2; + STRIP_ENUM_PREFIX_STRIP = 3; + } + + optional StripEnumPrefix strip_enum_prefix = 3 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_ENUM_ENTRY, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2024, + }, + // TODO: change the default to STRIP_ENUM_PREFIX_STRIP for edition 2025. + edition_defaults = { + edition: EDITION_LEGACY, + value: "STRIP_ENUM_PREFIX_KEEP" + } + ]; + + // Wrap the OptimizeMode enum in a message for scoping: + // This way, users can type shorter names (SPEED, CODE_SIZE). + message OptimizeModeFeature { + // The name of this enum matches OptimizeMode in descriptor.proto. + enum OptimizeMode { + // OPTIMIZE_MODE_UNSPECIFIED results in falling back to the default + // (optimize for code size), but needs to be a separate value to distinguish + // between an explicitly set optimize mode or a missing optimize mode. + OPTIMIZE_MODE_UNSPECIFIED = 0; + SPEED = 1; + CODE_SIZE = 2; + // There is no enum entry for LITE_RUNTIME (descriptor.proto), + // because Go Protobuf does not have the concept of a lite runtime. + } + } + + optional OptimizeModeFeature.OptimizeMode optimize_mode = 4 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2024, + }, + edition_defaults = { + edition: EDITION_LEGACY, + value: "OPTIMIZE_MODE_UNSPECIFIED" + } + ]; +} diff --git a/flow/proto/google/protobuf/java_features.proto b/flow/proto/google/protobuf/java_features.proto new file mode 100644 index 00000000000..80ac6fa9f11 --- /dev/null +++ b/flow/proto/google/protobuf/java_features.proto @@ -0,0 +1,132 @@ + +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +syntax = "proto2"; + +package pb; + +import "google/protobuf/descriptor.proto"; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "JavaFeaturesProto"; + +extend google.protobuf.FeatureSet { + optional JavaFeatures java = 1001; +} + +message JavaFeatures { + // Whether or not to treat an enum field as closed. This option is only + // applicable to enum fields, and will be removed in the future. It is + // consistent with the legacy behavior of using proto3 enum types for proto2 + // fields. + optional bool legacy_closed_enum = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + edition_deprecated: EDITION_2023, + deprecation_warning: "The legacy closed enum behavior in Java is " + "deprecated and is scheduled to be removed in " + "edition 2025. See http://protobuf.dev/programming-guides/enum/#java for " + "more information.", + }, + edition_defaults = { edition: EDITION_LEGACY, value: "true" }, + edition_defaults = { edition: EDITION_PROTO3, value: "false" } + ]; + + // The UTF8 validation strategy to use. + enum Utf8Validation { + // Invalid default, which should never be used. + UTF8_VALIDATION_UNKNOWN = 0; + // Respect the UTF8 validation behavior specified by the global + // utf8_validation feature. + DEFAULT = 1; + // Verifies UTF8 validity overriding the global utf8_validation + // feature. This represents the legacy java_string_check_utf8 option. + VERIFY = 2; + } + optional Utf8Validation utf8_validation = 2 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2023, + edition_deprecated: EDITION_2024, + deprecation_warning: "The Java-specific utf8 validation feature is " + "deprecated and is scheduled to be removed in " + "edition 2025. Utf8 validation behavior should " + "use the global cross-language utf8_validation " + "feature.", + }, + edition_defaults = { edition: EDITION_LEGACY, value: "DEFAULT" } + ]; + + // Allows creation of large Java enums, extending beyond the standard + // constant limits imposed by the Java language. + optional bool large_enum = 3 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2024, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "false" } + ]; + + // Whether to use the old default outer class name scheme, or the new feature + // which adds a "Proto" suffix to the outer class name. + // + // Users will not be able to set this option, because we removed it in the + // same edition that it was introduced. But we use it to determine which + // naming scheme to use for outer class name defaults. + optional bool use_old_outer_classname_default = 4 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FILE, + feature_support = { + edition_introduced: EDITION_2024, + edition_removed: EDITION_2024, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "true" }, + edition_defaults = { edition: EDITION_2024, value: "false" } + ]; + + message NestInFileClassFeature { + enum NestInFileClass { + // Invalid default, which should never be used. + NEST_IN_FILE_CLASS_UNKNOWN = 0; + // Do not nest the generated class in the file class. + NO = 1; + // Nest the generated class in the file class. + YES = 2; + // Fall back to the `java_multiple_files` option. Users won't be able to + // set this option. + LEGACY = 3 [feature_support = { + edition_introduced: EDITION_2024 + edition_removed: EDITION_2024 + }]; + } + reserved 1 to max; + } + + // Whether to nest the generated class in the generated file class. This is + // only applicable to *top-level* messages, enums, and services. + optional NestInFileClassFeature.NestInFileClass nest_in_file_class = 5 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_SERVICE, + feature_support = { + edition_introduced: EDITION_2024, + }, + edition_defaults = { edition: EDITION_LEGACY, value: "LEGACY" }, + edition_defaults = { edition: EDITION_2024, value: "NO" } + ]; + + reserved 6; // field `mutable_nest_in_file_class` removed. +} diff --git a/flow/proto/google/protobuf/source_context.proto b/flow/proto/google/protobuf/source_context.proto new file mode 100644 index 00000000000..135f50fea51 --- /dev/null +++ b/flow/proto/google/protobuf/source_context.proto @@ -0,0 +1,48 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "SourceContextProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; + +// `SourceContext` represents information about the source of a +// protobuf element, like the file in which it is defined. +message SourceContext { + // The path-qualified name of the .proto file that contained the associated + // protobuf element. For example: `"google/protobuf/source_context.proto"`. + string file_name = 1; +} diff --git a/flow/proto/google/protobuf/struct.proto b/flow/proto/google/protobuf/struct.proto new file mode 100644 index 00000000000..1bf0c1ad958 --- /dev/null +++ b/flow/proto/google/protobuf/struct.proto @@ -0,0 +1,95 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/structpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "StructProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; + +// `Struct` represents a structured data value, consisting of fields +// which map to dynamically typed values. In some languages, `Struct` +// might be supported by a native representation. For example, in +// scripting languages like JS a struct is represented as an +// object. The details of that representation are described together +// with the proto support for the language. +// +// The JSON representation for `Struct` is JSON object. +message Struct { + // Unordered map of dynamically typed values. + map fields = 1; +} + +// `Value` represents a dynamically typed value which can be either +// null, a number, a string, a boolean, a recursive struct value, or a +// list of values. A producer of value is expected to set one of these +// variants. Absence of any variant indicates an error. +// +// The JSON representation for `Value` is JSON value. +message Value { + // The kind of value. + oneof kind { + // Represents a null value. + NullValue null_value = 1; + // Represents a double value. + double number_value = 2; + // Represents a string value. + string string_value = 3; + // Represents a boolean value. + bool bool_value = 4; + // Represents a structured value. + Struct struct_value = 5; + // Represents a repeated `Value`. + ListValue list_value = 6; + } +} + +// `NullValue` is a singleton enumeration to represent the null value for the +// `Value` type union. +// +// The JSON representation for `NullValue` is JSON `null`. +enum NullValue { + // Null value. + NULL_VALUE = 0; +} + +// `ListValue` is a wrapper around a repeated field of values. +// +// The JSON representation for `ListValue` is JSON array. +message ListValue { + // Repeated field of dynamically typed values. + repeated Value values = 1; +} diff --git a/flow/proto/google/protobuf/timestamp.proto b/flow/proto/google/protobuf/timestamp.proto new file mode 100644 index 00000000000..6bc1efc6d60 --- /dev/null +++ b/flow/proto/google/protobuf/timestamp.proto @@ -0,0 +1,145 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/timestamppb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "TimestampProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; + +// A Timestamp represents a point in time independent of any time zone or local +// calendar, encoded as a count of seconds and fractions of seconds at +// nanosecond resolution. The count is relative to an epoch at UTC midnight on +// January 1, 1970, in the proleptic Gregorian calendar which extends the +// Gregorian calendar backwards to year one. +// +// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap +// second table is needed for interpretation, using a [24-hour linear +// smear](https://developers.google.com/time/smear). +// +// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By +// restricting to that range, we ensure that we can convert to and from [RFC +// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. +// +// # Examples +// +// Example 1: Compute Timestamp from POSIX `time()`. +// +// Timestamp timestamp; +// timestamp.set_seconds(time(NULL)); +// timestamp.set_nanos(0); +// +// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +// +// struct timeval tv; +// gettimeofday(&tv, NULL); +// +// Timestamp timestamp; +// timestamp.set_seconds(tv.tv_sec); +// timestamp.set_nanos(tv.tv_usec * 1000); +// +// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +// +// FILETIME ft; +// GetSystemTimeAsFileTime(&ft); +// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +// +// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +// Timestamp timestamp; +// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +// +// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +// +// long millis = System.currentTimeMillis(); +// +// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +// .setNanos((int) ((millis % 1000) * 1000000)).build(); +// +// Example 5: Compute Timestamp from Java `Instant.now()`. +// +// Instant now = Instant.now(); +// +// Timestamp timestamp = +// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) +// .setNanos(now.getNano()).build(); +// +// Example 6: Compute Timestamp from current time in Python. +// +// timestamp = Timestamp() +// timestamp.GetCurrentTime() +// +// # JSON Mapping +// +// In JSON format, the Timestamp type is encoded as a string in the +// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the +// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" +// where {year} is always expressed using four digits while {month}, {day}, +// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional +// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), +// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone +// is required. A ProtoJSON serializer should always use UTC (as indicated by +// "Z") when printing the Timestamp type and a ProtoJSON parser should be +// able to accept both UTC and other timezones (as indicated by an offset). +// +// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past +// 01:30 UTC on January 15, 2017. +// +// In JavaScript, one can convert a Date object to this format using the +// standard +// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) +// method. In Python, a standard `datetime.datetime` object can be converted +// to this format using +// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with +// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use +// the Joda Time's [`ISODateTimeFormat.dateTime()`]( +// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime() +// ) to obtain a formatter capable of generating timestamps in this format. +// +message Timestamp { + // Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must + // be between -62135596800 and 253402300799 inclusive (which corresponds to + // 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z). + int64 seconds = 1; + + // Non-negative fractions of a second at nanosecond resolution. This field is + // the nanosecond portion of the duration, not an alternative to seconds. + // Negative second values with fractions must still have non-negative nanos + // values that count forward in time. Must be between 0 and 999,999,999 + // inclusive. + int32 nanos = 2; +} diff --git a/flow/proto/google/protobuf/type.proto b/flow/proto/google/protobuf/type.proto new file mode 100644 index 00000000000..2c7615ed6d3 --- /dev/null +++ b/flow/proto/google/protobuf/type.proto @@ -0,0 +1,217 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +import "google/protobuf/any.proto"; +import "google/protobuf/source_context.proto"; + +option cc_enable_arenas = true; +option java_package = "com.google.protobuf"; +option java_outer_classname = "TypeProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "google.golang.org/protobuf/types/known/typepb"; + +// A protocol buffer message type. +// +// New usages of this message as an alternative to DescriptorProto are strongly +// discouraged. This message does not reliability preserve all information +// necessary to model the schema and preserve semantics. Instead make use of +// FileDescriptorSet which preserves the necessary information. +message Type { + // The fully qualified message name. + string name = 1; + // The list of fields. + repeated Field fields = 2; + // The list of types appearing in `oneof` definitions in this type. + repeated string oneofs = 3; + // The protocol buffer options. + repeated Option options = 4; + // The source context. + SourceContext source_context = 5; + // The source syntax. + Syntax syntax = 6; + // The source edition string, only valid when syntax is SYNTAX_EDITIONS. + string edition = 7; +} + +// A single field of a message type. +// +// New usages of this message as an alternative to FieldDescriptorProto are +// strongly discouraged. This message does not reliability preserve all +// information necessary to model the schema and preserve semantics. Instead +// make use of FileDescriptorSet which preserves the necessary information. +message Field { + // Basic field types. + enum Kind { + // Field type unknown. + TYPE_UNKNOWN = 0; + // Field type double. + TYPE_DOUBLE = 1; + // Field type float. + TYPE_FLOAT = 2; + // Field type int64. + TYPE_INT64 = 3; + // Field type uint64. + TYPE_UINT64 = 4; + // Field type int32. + TYPE_INT32 = 5; + // Field type fixed64. + TYPE_FIXED64 = 6; + // Field type fixed32. + TYPE_FIXED32 = 7; + // Field type bool. + TYPE_BOOL = 8; + // Field type string. + TYPE_STRING = 9; + // Field type group. Proto2 syntax only, and deprecated. + TYPE_GROUP = 10; + // Field type message. + TYPE_MESSAGE = 11; + // Field type bytes. + TYPE_BYTES = 12; + // Field type uint32. + TYPE_UINT32 = 13; + // Field type enum. + TYPE_ENUM = 14; + // Field type sfixed32. + TYPE_SFIXED32 = 15; + // Field type sfixed64. + TYPE_SFIXED64 = 16; + // Field type sint32. + TYPE_SINT32 = 17; + // Field type sint64. + TYPE_SINT64 = 18; + } + + // Whether a field is optional, required, or repeated. + enum Cardinality { + // For fields with unknown cardinality. + CARDINALITY_UNKNOWN = 0; + // For optional fields. + CARDINALITY_OPTIONAL = 1; + // For required fields. Proto2 syntax only. + CARDINALITY_REQUIRED = 2; + // For repeated fields. + CARDINALITY_REPEATED = 3; + } + + // The field type. + Kind kind = 1; + // The field cardinality. + Cardinality cardinality = 2; + // The field number. + int32 number = 3; + // The field name. + string name = 4; + // The field type URL, without the scheme, for message or enumeration + // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. + string type_url = 6; + // The index of the field type in `Type.oneofs`, for message or enumeration + // types. The first type has index 1; zero means the type is not in the list. + int32 oneof_index = 7; + // Whether to use alternative packed wire representation. + bool packed = 8; + // The protocol buffer options. + repeated Option options = 9; + // The field JSON name. + string json_name = 10; + // The string value of the default value of this field. Proto2 syntax only. + string default_value = 11; +} + +// Enum type definition. +// +// New usages of this message as an alternative to EnumDescriptorProto are +// strongly discouraged. This message does not reliability preserve all +// information necessary to model the schema and preserve semantics. Instead +// make use of FileDescriptorSet which preserves the necessary information. +message Enum { + // Enum type name. + string name = 1; + // Enum value definitions. + repeated EnumValue enumvalue = 2; + // Protocol buffer options. + repeated Option options = 3; + // The source context. + SourceContext source_context = 4; + // The source syntax. + Syntax syntax = 5; + // The source edition string, only valid when syntax is SYNTAX_EDITIONS. + string edition = 6; +} + +// Enum value definition. +// +// New usages of this message as an alternative to EnumValueDescriptorProto are +// strongly discouraged. This message does not reliability preserve all +// information necessary to model the schema and preserve semantics. Instead +// make use of FileDescriptorSet which preserves the necessary information. +message EnumValue { + // Enum value name. + string name = 1; + // Enum value number. + int32 number = 2; + // Protocol buffer options. + repeated Option options = 3; +} + +// A protocol buffer option, which can be attached to a message, field, +// enumeration, etc. +// +// New usages of this message as an alternative to FileOptions, MessageOptions, +// FieldOptions, EnumOptions, EnumValueOptions, ServiceOptions, or MethodOptions +// are strongly discouraged. +message Option { + // The option's name. For protobuf built-in options (options defined in + // descriptor.proto), this is the short name. For example, `"map_entry"`. + // For custom options, it should be the fully-qualified name. For example, + // `"google.api.http"`. + string name = 1; + // The option's value packed in an Any message. If the value is a primitive, + // the corresponding wrapper type defined in google/protobuf/wrappers.proto + // should be used. If the value is an enum, it should be stored as an int32 + // value using the google.protobuf.Int32Value type. + Any value = 2; +} + +// The syntax in which a protocol buffer element is defined. +enum Syntax { + // Syntax `proto2`. + SYNTAX_PROTO2 = 0; + // Syntax `proto3`. + SYNTAX_PROTO3 = 1; + // Syntax `editions`. + SYNTAX_EDITIONS = 2; +} diff --git a/flow/proto/google/protobuf/wrappers.proto b/flow/proto/google/protobuf/wrappers.proto new file mode 100644 index 00000000000..e583e7c40be --- /dev/null +++ b/flow/proto/google/protobuf/wrappers.proto @@ -0,0 +1,157 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Wrappers for primitive (non-message) types. These types were needed +// for legacy reasons and are not recommended for use in new APIs. +// +// Historically these wrappers were useful to have presence on proto3 primitive +// fields, but proto3 syntax has been updated to support the `optional` keyword. +// Using that keyword is now the strongly preferred way to add presence to +// proto3 primitive fields. +// +// A secondary usecase was to embed primitives in the `google.protobuf.Any` +// type: it is now recommended that you embed your value in your own wrapper +// message which can be specifically documented. +// +// These wrappers have no meaningful use within repeated fields as they lack +// the ability to detect presence on individual elements. +// These wrappers have no meaningful use within a map or a oneof since +// individual entries of a map or fields of a oneof can already detect presence. + +syntax = "proto3"; + +package google.protobuf; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "WrappersProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; + +// Wrapper message for `double`. +// +// The JSON representation for `DoubleValue` is JSON number. +// +// Not recommended for use in new APIs, but still useful for legacy APIs and +// has no plan to be removed. +message DoubleValue { + // The double value. + double value = 1; +} + +// Wrapper message for `float`. +// +// The JSON representation for `FloatValue` is JSON number. +// +// Not recommended for use in new APIs, but still useful for legacy APIs and +// has no plan to be removed. +message FloatValue { + // The float value. + float value = 1; +} + +// Wrapper message for `int64`. +// +// The JSON representation for `Int64Value` is JSON string. +// +// Not recommended for use in new APIs, but still useful for legacy APIs and +// has no plan to be removed. +message Int64Value { + // The int64 value. + int64 value = 1; +} + +// Wrapper message for `uint64`. +// +// The JSON representation for `UInt64Value` is JSON string. +// +// Not recommended for use in new APIs, but still useful for legacy APIs and +// has no plan to be removed. +message UInt64Value { + // The uint64 value. + uint64 value = 1; +} + +// Wrapper message for `int32`. +// +// The JSON representation for `Int32Value` is JSON number. +// +// Not recommended for use in new APIs, but still useful for legacy APIs and +// has no plan to be removed. +message Int32Value { + // The int32 value. + int32 value = 1; +} + +// Wrapper message for `uint32`. +// +// The JSON representation for `UInt32Value` is JSON number. +// +// Not recommended for use in new APIs, but still useful for legacy APIs and +// has no plan to be removed. +message UInt32Value { + // The uint32 value. + uint32 value = 1; +} + +// Wrapper message for `bool`. +// +// The JSON representation for `BoolValue` is JSON `true` and `false`. +// +// Not recommended for use in new APIs, but still useful for legacy APIs and +// has no plan to be removed. +message BoolValue { + // The bool value. + bool value = 1; +} + +// Wrapper message for `string`. +// +// The JSON representation for `StringValue` is JSON string. +// +// Not recommended for use in new APIs, but still useful for legacy APIs and +// has no plan to be removed. +message StringValue { + // The string value. + string value = 1; +} + +// Wrapper message for `bytes`. +// +// The JSON representation for `BytesValue` is JSON string. +// +// Not recommended for use in new APIs, but still useful for legacy APIs and +// has no plan to be removed. +message BytesValue { + // The bytes value. + bytes value = 1; +} From a593e32a1ddcb481b85cccbb1a986d6789bd4e41 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Thu, 11 Jun 2026 12:07:29 +0200 Subject: [PATCH 08/30] removed inadvertenly added google proto files Signed-off-by: Dmitri --- flow/proto/google/protobuf/any.proto | 162 -- flow/proto/google/protobuf/api.proto | 229 --- .../google/protobuf/compiler/plugin.proto | 180 -- flow/proto/google/protobuf/cpp_features.proto | 67 - flow/proto/google/protobuf/descriptor.proto | 1448 ----------------- flow/proto/google/protobuf/duration.proto | 115 -- flow/proto/google/protobuf/empty.proto | 51 - flow/proto/google/protobuf/field_mask.proto | 243 --- flow/proto/google/protobuf/go_features.proto | 112 -- .../proto/google/protobuf/java_features.proto | 132 -- .../google/protobuf/source_context.proto | 48 - flow/proto/google/protobuf/struct.proto | 95 -- flow/proto/google/protobuf/timestamp.proto | 145 -- flow/proto/google/protobuf/type.proto | 217 --- flow/proto/google/protobuf/wrappers.proto | 157 -- 15 files changed, 3401 deletions(-) delete mode 100644 flow/proto/google/protobuf/any.proto delete mode 100644 flow/proto/google/protobuf/api.proto delete mode 100644 flow/proto/google/protobuf/compiler/plugin.proto delete mode 100644 flow/proto/google/protobuf/cpp_features.proto delete mode 100644 flow/proto/google/protobuf/descriptor.proto delete mode 100644 flow/proto/google/protobuf/duration.proto delete mode 100644 flow/proto/google/protobuf/empty.proto delete mode 100644 flow/proto/google/protobuf/field_mask.proto delete mode 100644 flow/proto/google/protobuf/go_features.proto delete mode 100644 flow/proto/google/protobuf/java_features.proto delete mode 100644 flow/proto/google/protobuf/source_context.proto delete mode 100644 flow/proto/google/protobuf/struct.proto delete mode 100644 flow/proto/google/protobuf/timestamp.proto delete mode 100644 flow/proto/google/protobuf/type.proto delete mode 100644 flow/proto/google/protobuf/wrappers.proto diff --git a/flow/proto/google/protobuf/any.proto b/flow/proto/google/protobuf/any.proto deleted file mode 100644 index eff44e5099d..00000000000 --- a/flow/proto/google/protobuf/any.proto +++ /dev/null @@ -1,162 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option go_package = "google.golang.org/protobuf/types/known/anypb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "AnyProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// `Any` contains an arbitrary serialized protocol buffer message along with a -// URL that describes the type of the serialized message. -// -// Protobuf library provides support to pack/unpack Any values in the form -// of utility functions or additional generated methods of the Any type. -// -// Example 1: Pack and unpack a message in C++. -// -// Foo foo = ...; -// Any any; -// any.PackFrom(foo); -// ... -// if (any.UnpackTo(&foo)) { -// ... -// } -// -// Example 2: Pack and unpack a message in Java. -// -// Foo foo = ...; -// Any any = Any.pack(foo); -// ... -// if (any.is(Foo.class)) { -// foo = any.unpack(Foo.class); -// } -// // or ... -// if (any.isSameTypeAs(Foo.getDefaultInstance())) { -// foo = any.unpack(Foo.getDefaultInstance()); -// } -// -// Example 3: Pack and unpack a message in Python. -// -// foo = Foo(...) -// any = Any() -// any.Pack(foo) -// ... -// if any.Is(Foo.DESCRIPTOR): -// any.Unpack(foo) -// ... -// -// Example 4: Pack and unpack a message in Go -// -// foo := &pb.Foo{...} -// any, err := anypb.New(foo) -// if err != nil { -// ... -// } -// ... -// foo := &pb.Foo{} -// if err := any.UnmarshalTo(foo); err != nil { -// ... -// } -// -// The pack methods provided by protobuf library will by default use -// 'type.googleapis.com/full.type.name' as the type URL and the unpack -// methods only use the fully qualified type name after the last '/' -// in the type URL, for example "foo.bar.com/x/y.z" will yield type -// name "y.z". -// -// JSON -// ==== -// The JSON representation of an `Any` value uses the regular -// representation of the deserialized, embedded message, with an -// additional field `@type` which contains the type URL. Example: -// -// package google.profile; -// message Person { -// string first_name = 1; -// string last_name = 2; -// } -// -// { -// "@type": "type.googleapis.com/google.profile.Person", -// "firstName": , -// "lastName": -// } -// -// If the embedded message type is well-known and has a custom JSON -// representation, that representation will be embedded adding a field -// `value` which holds the custom JSON in addition to the `@type` -// field. Example (for message [google.protobuf.Duration][]): -// -// { -// "@type": "type.googleapis.com/google.protobuf.Duration", -// "value": "1.212s" -// } -// -message Any { - // A URL/resource name that uniquely identifies the type of the serialized - // protocol buffer message. This string must contain at least - // one "/" character. The last segment of the URL's path must represent - // the fully qualified name of the type (as in - // `path/google.protobuf.Duration`). The name should be in a canonical form - // (e.g., leading "." is not accepted). - // - // In practice, teams usually precompile into the binary all types that they - // expect it to use in the context of Any. However, for URLs which use the - // scheme `http`, `https`, or no scheme, one can optionally set up a type - // server that maps type URLs to message definitions as follows: - // - // * If no scheme is provided, `https` is assumed. - // * An HTTP GET on the URL must yield a [google.protobuf.Type][] - // value in binary format, or produce an error. - // * Applications are allowed to cache lookup results based on the - // URL, or have them precompiled into a binary to avoid any - // lookup. Therefore, binary compatibility needs to be preserved - // on changes to types. (Use versioned type names to manage - // breaking changes.) - // - // Note: this functionality is not currently available in the official - // protobuf release, and it is not used for type URLs beginning with - // type.googleapis.com. As of May 2023, there are no widely used type server - // implementations and no plans to implement one. - // - // Schemes other than `http`, `https` (or the empty scheme) might be - // used with implementation specific semantics. - // - string type_url = 1; - - // Must be a valid serialized protocol buffer of the above specified type. - bytes value = 2; -} diff --git a/flow/proto/google/protobuf/api.proto b/flow/proto/google/protobuf/api.proto deleted file mode 100644 index c8f742543c7..00000000000 --- a/flow/proto/google/protobuf/api.proto +++ /dev/null @@ -1,229 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -import "google/protobuf/source_context.proto"; -import "google/protobuf/type.proto"; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "ApiProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/apipb"; - -// Api is a light-weight descriptor for an API Interface. -// -// Interfaces are also described as "protocol buffer services" in some contexts, -// such as by the "service" keyword in a .proto file, but they are different -// from API Services, which represent a concrete implementation of an interface -// as opposed to simply a description of methods and bindings. They are also -// sometimes simply referred to as "APIs" in other contexts, such as the name of -// this message itself. See https://cloud.google.com/apis/design/glossary for -// detailed terminology. -// -// New usages of this message as an alternative to ServiceDescriptorProto are -// strongly discouraged. This message does not reliability preserve all -// information necessary to model the schema and preserve semantics. Instead -// make use of FileDescriptorSet which preserves the necessary information. -message Api { - // The fully qualified name of this interface, including package name - // followed by the interface's simple name. - string name = 1; - - // The methods of this interface, in unspecified order. - repeated Method methods = 2; - - // Any metadata attached to the interface. - repeated Option options = 3; - - // A version string for this interface. If specified, must have the form - // `major-version.minor-version`, as in `1.10`. If the minor version is - // omitted, it defaults to zero. If the entire version field is empty, the - // major version is derived from the package name, as outlined below. If the - // field is not empty, the version in the package name will be verified to be - // consistent with what is provided here. - // - // The versioning schema uses [semantic - // versioning](http://semver.org) where the major version number - // indicates a breaking change and the minor version an additive, - // non-breaking change. Both version numbers are signals to users - // what to expect from different versions, and should be carefully - // chosen based on the product plan. - // - // The major version is also reflected in the package name of the - // interface, which must end in `v`, as in - // `google.feature.v1`. For major versions 0 and 1, the suffix can - // be omitted. Zero major versions must only be used for - // experimental, non-GA interfaces. - // - string version = 4; - - // Source context for the protocol buffer service represented by this - // message. - SourceContext source_context = 5; - - // Included interfaces. See [Mixin][]. - repeated Mixin mixins = 6; - - // The source syntax of the service. - Syntax syntax = 7; - - // The source edition string, only valid when syntax is SYNTAX_EDITIONS. - string edition = 8; -} - -// Method represents a method of an API interface. -// -// New usages of this message as an alternative to MethodDescriptorProto are -// strongly discouraged. This message does not reliability preserve all -// information necessary to model the schema and preserve semantics. Instead -// make use of FileDescriptorSet which preserves the necessary information. -message Method { - // The simple name of this method. - string name = 1; - - // A URL of the input message type. - string request_type_url = 2; - - // If true, the request is streamed. - bool request_streaming = 3; - - // The URL of the output message type. - string response_type_url = 4; - - // If true, the response is streamed. - bool response_streaming = 5; - - // Any metadata attached to the method. - repeated Option options = 6; - - // The source syntax of this method. - // - // This field should be ignored, instead the syntax should be inherited from - // Api. This is similar to Field and EnumValue. - Syntax syntax = 7 [deprecated = true]; - - // The source edition string, only valid when syntax is SYNTAX_EDITIONS. - // - // This field should be ignored, instead the edition should be inherited from - // Api. This is similar to Field and EnumValue. - string edition = 8 [deprecated = true]; -} - -// Declares an API Interface to be included in this interface. The including -// interface must redeclare all the methods from the included interface, but -// documentation and options are inherited as follows: -// -// - If after comment and whitespace stripping, the documentation -// string of the redeclared method is empty, it will be inherited -// from the original method. -// -// - Each annotation belonging to the service config (http, -// visibility) which is not set in the redeclared method will be -// inherited. -// -// - If an http annotation is inherited, the path pattern will be -// modified as follows. Any version prefix will be replaced by the -// version of the including interface plus the [root][] path if -// specified. -// -// Example of a simple mixin: -// -// package google.acl.v1; -// service AccessControl { -// // Get the underlying ACL object. -// rpc GetAcl(GetAclRequest) returns (Acl) { -// option (google.api.http).get = "/v1/{resource=**}:getAcl"; -// } -// } -// -// package google.storage.v2; -// service Storage { -// rpc GetAcl(GetAclRequest) returns (Acl); -// -// // Get a data record. -// rpc GetData(GetDataRequest) returns (Data) { -// option (google.api.http).get = "/v2/{resource=**}"; -// } -// } -// -// Example of a mixin configuration: -// -// apis: -// - name: google.storage.v2.Storage -// mixins: -// - name: google.acl.v1.AccessControl -// -// The mixin construct implies that all methods in `AccessControl` are -// also declared with same name and request/response types in -// `Storage`. A documentation generator or annotation processor will -// see the effective `Storage.GetAcl` method after inheriting -// documentation and annotations as follows: -// -// service Storage { -// // Get the underlying ACL object. -// rpc GetAcl(GetAclRequest) returns (Acl) { -// option (google.api.http).get = "/v2/{resource=**}:getAcl"; -// } -// ... -// } -// -// Note how the version in the path pattern changed from `v1` to `v2`. -// -// If the `root` field in the mixin is specified, it should be a -// relative path under which inherited HTTP paths are placed. Example: -// -// apis: -// - name: google.storage.v2.Storage -// mixins: -// - name: google.acl.v1.AccessControl -// root: acls -// -// This implies the following inherited HTTP annotation: -// -// service Storage { -// // Get the underlying ACL object. -// rpc GetAcl(GetAclRequest) returns (Acl) { -// option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; -// } -// ... -// } -message Mixin { - // The fully qualified name of the interface which is included. - string name = 1; - - // If non-empty specifies a path under which inherited HTTP paths - // are rooted. - string root = 2; -} diff --git a/flow/proto/google/protobuf/compiler/plugin.proto b/flow/proto/google/protobuf/compiler/plugin.proto deleted file mode 100644 index 10d285f8a54..00000000000 --- a/flow/proto/google/protobuf/compiler/plugin.proto +++ /dev/null @@ -1,180 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -// Author: kenton@google.com (Kenton Varda) -// -// protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is -// just a program that reads a CodeGeneratorRequest from stdin and writes a -// CodeGeneratorResponse to stdout. -// -// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead -// of dealing with the raw protocol defined here. -// -// A plugin executable needs only to be placed somewhere in the path. The -// plugin should be named "protoc-gen-$NAME", and will then be used when the -// flag "--${NAME}_out" is passed to protoc. - -syntax = "proto2"; - -package google.protobuf.compiler; -option java_package = "com.google.protobuf.compiler"; -option java_outer_classname = "PluginProtos"; - -import "google/protobuf/descriptor.proto"; - -option csharp_namespace = "Google.Protobuf.Compiler"; -option go_package = "google.golang.org/protobuf/types/pluginpb"; - -// The version number of protocol compiler. -message Version { - optional int32 major = 1; - optional int32 minor = 2; - optional int32 patch = 3; - // A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should - // be empty for mainline stable releases. - optional string suffix = 4; -} - -// An encoded CodeGeneratorRequest is written to the plugin's stdin. -message CodeGeneratorRequest { - // The .proto files that were explicitly listed on the command-line. The - // code generator should generate code only for these files. Each file's - // descriptor will be included in proto_file, below. - repeated string file_to_generate = 1; - - // The generator parameter passed on the command-line. - optional string parameter = 2; - - // FileDescriptorProtos for all files in files_to_generate and everything - // they import. The files will appear in topological order, so each file - // appears before any file that imports it. - // - // Note: the files listed in files_to_generate will include runtime-retention - // options only, but all other files will include source-retention options. - // The source_file_descriptors field below is available in case you need - // source-retention options for files_to_generate. - // - // protoc guarantees that all proto_files will be written after - // the fields above, even though this is not technically guaranteed by the - // protobuf wire format. This theoretically could allow a plugin to stream - // in the FileDescriptorProtos and handle them one by one rather than read - // the entire set into memory at once. However, as of this writing, this - // is not similarly optimized on protoc's end -- it will store all fields in - // memory at once before sending them to the plugin. - // - // Type names of fields and extensions in the FileDescriptorProto are always - // fully qualified. - repeated FileDescriptorProto proto_file = 15; - - // File descriptors with all options, including source-retention options. - // These descriptors are only provided for the files listed in - // files_to_generate. - repeated FileDescriptorProto source_file_descriptors = 17; - - // The version number of protocol compiler. - optional Version compiler_version = 3; -} - -// The plugin writes an encoded CodeGeneratorResponse to stdout. -message CodeGeneratorResponse { - // Error message. If non-empty, code generation failed. The plugin process - // should exit with status code zero even if it reports an error in this way. - // - // This should be used to indicate errors in .proto files which prevent the - // code generator from generating correct code. Errors which indicate a - // problem in protoc itself -- such as the input CodeGeneratorRequest being - // unparseable -- should be reported by writing a message to stderr and - // exiting with a non-zero status code. - optional string error = 1; - - // A bitmask of supported features that the code generator supports. - // This is a bitwise "or" of values from the Feature enum. - optional uint64 supported_features = 2; - - // Sync with code_generator.h. - enum Feature { - FEATURE_NONE = 0; - FEATURE_PROTO3_OPTIONAL = 1; - FEATURE_SUPPORTS_EDITIONS = 2; - } - - // The minimum edition this plugin supports. This will be treated as an - // Edition enum, but we want to allow unknown values. It should be specified - // according the edition enum value, *not* the edition number. Only takes - // effect for plugins that have FEATURE_SUPPORTS_EDITIONS set. - optional int32 minimum_edition = 3; - - // The maximum edition this plugin supports. This will be treated as an - // Edition enum, but we want to allow unknown values. It should be specified - // according the edition enum value, *not* the edition number. Only takes - // effect for plugins that have FEATURE_SUPPORTS_EDITIONS set. - optional int32 maximum_edition = 4; - - // Represents a single generated file. - message File { - // The file name, relative to the output directory. The name must not - // contain "." or ".." components and must be relative, not be absolute (so, - // the file cannot lie outside the output directory). "/" must be used as - // the path separator, not "\". - // - // If the name is omitted, the content will be appended to the previous - // file. This allows the generator to break large files into small chunks, - // and allows the generated text to be streamed back to protoc so that large - // files need not reside completely in memory at one time. Note that as of - // this writing protoc does not optimize for this -- it will read the entire - // CodeGeneratorResponse before writing files to disk. - optional string name = 1; - - // If non-empty, indicates that the named file should already exist, and the - // content here is to be inserted into that file at a defined insertion - // point. This feature allows a code generator to extend the output - // produced by another code generator. The original generator may provide - // insertion points by placing special annotations in the file that look - // like: - // @@protoc_insertion_point(NAME) - // The annotation can have arbitrary text before and after it on the line, - // which allows it to be placed in a comment. NAME should be replaced with - // an identifier naming the point -- this is what other generators will use - // as the insertion_point. Code inserted at this point will be placed - // immediately above the line containing the insertion point (thus multiple - // insertions to the same point will come out in the order they were added). - // The double-@ is intended to make it unlikely that the generated code - // could contain things that look like insertion points by accident. - // - // For example, the C++ code generator places the following line in the - // .pb.h files that it generates: - // // @@protoc_insertion_point(namespace_scope) - // This line appears within the scope of the file's package namespace, but - // outside of any particular class. Another plugin can then specify the - // insertion_point "namespace_scope" to generate additional classes or - // other declarations that should be placed in this scope. - // - // Note that if the line containing the insertion point begins with - // whitespace, the same whitespace will be added to every line of the - // inserted text. This is useful for languages like Python, where - // indentation matters. In these languages, the insertion point comment - // should be indented the same amount as any inserted code will need to be - // in order to work correctly in that context. - // - // The code generator that generates the initial file and the one which - // inserts into it must both run as part of a single invocation of protoc. - // Code generators are executed in the order in which they appear on the - // command line. - // - // If |insertion_point| is present, |name| must also be present. - optional string insertion_point = 2; - - // The file contents. - optional string content = 15; - - // Information describing the file content being inserted. If an insertion - // point is used, this information will be appropriately offset and inserted - // into the code generation metadata for the generated files. - optional GeneratedCodeInfo generated_code_info = 16; - } - repeated File file = 15; -} diff --git a/flow/proto/google/protobuf/cpp_features.proto b/flow/proto/google/protobuf/cpp_features.proto deleted file mode 100644 index 75bf6b859af..00000000000 --- a/flow/proto/google/protobuf/cpp_features.proto +++ /dev/null @@ -1,67 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2023 Google Inc. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -syntax = "proto2"; - -package pb; - -import "google/protobuf/descriptor.proto"; - -extend google.protobuf.FeatureSet { - optional CppFeatures cpp = 1000; -} - -message CppFeatures { - // Whether or not to treat an enum field as closed. This option is only - // applicable to enum fields, and will be removed in the future. It is - // consistent with the legacy behavior of using proto3 enum types for proto2 - // fields. - optional bool legacy_closed_enum = 1 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - edition_deprecated: EDITION_2023, - deprecation_warning: "The legacy closed enum behavior in C++ is " - "deprecated and is scheduled to be removed in " - "edition 2025. See http://protobuf.dev/programming-guides/enum/#cpp for " - "more information", - }, - edition_defaults = { edition: EDITION_LEGACY, value: "true" }, - edition_defaults = { edition: EDITION_PROTO3, value: "false" } - ]; - - enum StringType { - STRING_TYPE_UNKNOWN = 0; - VIEW = 1; - CORD = 2; - STRING = 3; - } - - optional StringType string_type = 2 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "STRING" }, - edition_defaults = { edition: EDITION_2024, value: "VIEW" } - ]; - - optional bool enum_name_uses_string_view = 3 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_ENUM, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2024, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "false" }, - edition_defaults = { edition: EDITION_2024, value: "true" } - ]; -} diff --git a/flow/proto/google/protobuf/descriptor.proto b/flow/proto/google/protobuf/descriptor.proto deleted file mode 100644 index e5683a271ea..00000000000 --- a/flow/proto/google/protobuf/descriptor.proto +++ /dev/null @@ -1,1448 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. -// -// The messages in this file describe the definitions found in .proto files. -// A valid .proto file can be translated directly to a FileDescriptorProto -// without any other information (e.g. without reading its imports). - -syntax = "proto2"; - -package google.protobuf; - -option go_package = "google.golang.org/protobuf/types/descriptorpb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "DescriptorProtos"; -option csharp_namespace = "Google.Protobuf.Reflection"; -option objc_class_prefix = "GPB"; -option cc_enable_arenas = true; - -// descriptor.proto must be optimized for speed because reflection-based -// algorithms don't work during bootstrapping. -option optimize_for = SPEED; - -// The protocol compiler can output a FileDescriptorSet containing the .proto -// files it parses. -message FileDescriptorSet { - repeated FileDescriptorProto file = 1; - - // Extensions for tooling. - extensions 536000000 [declaration = { - number: 536000000 - type: ".buf.descriptor.v1.FileDescriptorSetExtension" - full_name: ".buf.descriptor.v1.buf_file_descriptor_set_extension" - }]; -} - -// The full set of known editions. -enum Edition { - // A placeholder for an unknown edition value. - EDITION_UNKNOWN = 0; - - // A placeholder edition for specifying default behaviors *before* a feature - // was first introduced. This is effectively an "infinite past". - EDITION_LEGACY = 900; - - // Legacy syntax "editions". These pre-date editions, but behave much like - // distinct editions. These can't be used to specify the edition of proto - // files, but feature definitions must supply proto2/proto3 defaults for - // backwards compatibility. - EDITION_PROTO2 = 998; - EDITION_PROTO3 = 999; - - // Editions that have been released. The specific values are arbitrary and - // should not be depended on, but they will always be time-ordered for easy - // comparison. - EDITION_2023 = 1000; - EDITION_2024 = 1001; - - // A placeholder edition for developing and testing unscheduled features. - EDITION_UNSTABLE = 9999; - - // Placeholder editions for testing feature resolution. These should not be - // used or relied on outside of tests. - EDITION_1_TEST_ONLY = 1; - EDITION_2_TEST_ONLY = 2; - EDITION_99997_TEST_ONLY = 99997; - EDITION_99998_TEST_ONLY = 99998; - EDITION_99999_TEST_ONLY = 99999; - - // Placeholder for specifying unbounded edition support. This should only - // ever be used by plugins that can expect to never require any changes to - // support a new edition. - EDITION_MAX = 0x7FFFFFFF; -} - -// Describes a complete .proto file. -message FileDescriptorProto { - optional string name = 1; // file name, relative to root of source tree - optional string package = 2; // e.g. "foo", "foo.bar", etc. - - // Names of files imported by this file. - repeated string dependency = 3; - // Indexes of the public imported files in the dependency list above. - repeated int32 public_dependency = 10; - // Indexes of the weak imported files in the dependency list. - // For Google-internal migration only. Do not use. - repeated int32 weak_dependency = 11; - - // Names of files imported by this file purely for the purpose of providing - // option extensions. These are excluded from the dependency list above. - repeated string option_dependency = 15; - - // All top-level definitions in this file. - repeated DescriptorProto message_type = 4; - repeated EnumDescriptorProto enum_type = 5; - repeated ServiceDescriptorProto service = 6; - repeated FieldDescriptorProto extension = 7; - - optional FileOptions options = 8; - - // This field contains optional information about the original source code. - // You may safely remove this entire field without harming runtime - // functionality of the descriptors -- the information is needed only by - // development tools. - optional SourceCodeInfo source_code_info = 9; - - // The syntax of the proto file. - // The supported values are "proto2", "proto3", and "editions". - // - // If `edition` is present, this value must be "editions". - // WARNING: This field should only be used by protobuf plugins or special - // cases like the proto compiler. Other uses are discouraged and - // developers should rely on the protoreflect APIs for their client language. - optional string syntax = 12; - - // The edition of the proto file. - // WARNING: This field should only be used by protobuf plugins or special - // cases like the proto compiler. Other uses are discouraged and - // developers should rely on the protoreflect APIs for their client language. - optional Edition edition = 14; -} - -// Describes a message type. -message DescriptorProto { - optional string name = 1; - - repeated FieldDescriptorProto field = 2; - repeated FieldDescriptorProto extension = 6; - - repeated DescriptorProto nested_type = 3; - repeated EnumDescriptorProto enum_type = 4; - - message ExtensionRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Exclusive. - - optional ExtensionRangeOptions options = 3; - } - repeated ExtensionRange extension_range = 5; - - repeated OneofDescriptorProto oneof_decl = 8; - - optional MessageOptions options = 7; - - // Range of reserved tag numbers. Reserved tag numbers may not be used by - // fields or extension ranges in the same message. Reserved ranges may - // not overlap. - message ReservedRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Exclusive. - } - repeated ReservedRange reserved_range = 9; - // Reserved field names, which may not be used by fields in the same message. - // A given name may only be reserved once. - repeated string reserved_name = 10; - - // Support for `export` and `local` keywords on enums. - optional SymbolVisibility visibility = 11; -} - -message ExtensionRangeOptions { - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - message Declaration { - // The extension number declared within the extension range. - optional int32 number = 1; - - // The fully-qualified name of the extension field. There must be a leading - // dot in front of the full name. - optional string full_name = 2; - - // The fully-qualified type name of the extension field. Unlike - // Metadata.type, Declaration.type must have a leading dot for messages - // and enums. - optional string type = 3; - - // If true, indicates that the number is reserved in the extension range, - // and any extension field with the number will fail to compile. Set this - // when a declared extension field is deleted. - optional bool reserved = 5; - - // If true, indicates that the extension must be defined as repeated. - // Otherwise the extension must be defined as optional. - optional bool repeated = 6; - - reserved 4; // removed is_repeated - } - - // For external users: DO NOT USE. We are in the process of open sourcing - // extension declaration and executing internal cleanups before it can be - // used externally. - repeated Declaration declaration = 2 [retention = RETENTION_SOURCE]; - - // Any features defined in the specific edition. - optional FeatureSet features = 50; - - // The verification state of the extension range. - enum VerificationState { - // All the extensions of the range must be declared. - DECLARATION = 0; - UNVERIFIED = 1; - } - - // The verification state of the range. - // TODO: flip the default to DECLARATION once all empty ranges - // are marked as UNVERIFIED. - optional VerificationState verification = 3 - [default = UNVERIFIED, retention = RETENTION_SOURCE]; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -// Describes a field within a message. -message FieldDescriptorProto { - enum Type { - // 0 is reserved for errors. - // Order is weird for historical reasons. - TYPE_DOUBLE = 1; - TYPE_FLOAT = 2; - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if - // negative values are likely. - TYPE_INT64 = 3; - TYPE_UINT64 = 4; - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if - // negative values are likely. - TYPE_INT32 = 5; - TYPE_FIXED64 = 6; - TYPE_FIXED32 = 7; - TYPE_BOOL = 8; - TYPE_STRING = 9; - // Tag-delimited aggregate. - // Group type is deprecated and not supported after google.protobuf. However, Proto3 - // implementations should still be able to parse the group wire format and - // treat group fields as unknown fields. In Editions, the group wire format - // can be enabled via the `message_encoding` feature. - TYPE_GROUP = 10; - TYPE_MESSAGE = 11; // Length-delimited aggregate. - - // New in version 2. - TYPE_BYTES = 12; - TYPE_UINT32 = 13; - TYPE_ENUM = 14; - TYPE_SFIXED32 = 15; - TYPE_SFIXED64 = 16; - TYPE_SINT32 = 17; // Uses ZigZag encoding. - TYPE_SINT64 = 18; // Uses ZigZag encoding. - } - - enum Label { - // 0 is reserved for errors - LABEL_OPTIONAL = 1; - LABEL_REPEATED = 3; - // The required label is only allowed in google.protobuf. In proto3 and Editions - // it's explicitly prohibited. In Editions, the `field_presence` feature - // can be used to get this behavior. - LABEL_REQUIRED = 2; - } - - optional string name = 1; - optional int32 number = 3; - optional Label label = 4; - - // If type_name is set, this need not be set. If both this and type_name - // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. - optional Type type = 5; - - // For message and enum types, this is the name of the type. If the name - // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping - // rules are used to find the type (i.e. first the nested types within this - // message are searched, then within the parent, on up to the root - // namespace). - optional string type_name = 6; - - // For extensions, this is the name of the type being extended. It is - // resolved in the same manner as type_name. - optional string extendee = 2; - - // For numeric types, contains the original text representation of the value. - // For booleans, "true" or "false". - // For strings, contains the default text contents (not escaped in any way). - // For bytes, contains the C escaped value. All bytes >= 128 are escaped. - optional string default_value = 7; - - // If set, gives the index of a oneof in the containing type's oneof_decl - // list. This field is a member of that oneof. - optional int32 oneof_index = 9; - - // JSON name of this field. The value is set by protocol compiler. If the - // user has set a "json_name" option on this field, that option's value - // will be used. Otherwise, it's deduced from the field's name by converting - // it to camelCase. - optional string json_name = 10; - - optional FieldOptions options = 8; - - // If true, this is a proto3 "optional". When a proto3 field is optional, it - // tracks presence regardless of field type. - // - // When proto3_optional is true, this field must belong to a oneof to signal - // to old proto3 clients that presence is tracked for this field. This oneof - // is known as a "synthetic" oneof, and this field must be its sole member - // (each proto3 optional field gets its own synthetic oneof). Synthetic oneofs - // exist in the descriptor only, and do not generate any API. Synthetic oneofs - // must be ordered after all "real" oneofs. - // - // For message fields, proto3_optional doesn't create any semantic change, - // since non-repeated message fields always track presence. However it still - // indicates the semantic detail of whether the user wrote "optional" or not. - // This can be useful for round-tripping the .proto file. For consistency we - // give message fields a synthetic oneof also, even though it is not required - // to track presence. This is especially important because the parser can't - // tell if a field is a message or an enum, so it must always create a - // synthetic oneof. - // - // Proto2 optional fields do not set this flag, because they already indicate - // optional with `LABEL_OPTIONAL`. - optional bool proto3_optional = 17; -} - -// Describes a oneof. -message OneofDescriptorProto { - optional string name = 1; - optional OneofOptions options = 2; -} - -// Describes an enum type. -message EnumDescriptorProto { - optional string name = 1; - - repeated EnumValueDescriptorProto value = 2; - - optional EnumOptions options = 3; - - // Range of reserved numeric values. Reserved values may not be used by - // entries in the same enum. Reserved ranges may not overlap. - // - // Note that this is distinct from DescriptorProto.ReservedRange in that it - // is inclusive such that it can appropriately represent the entire int32 - // domain. - message EnumReservedRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Inclusive. - } - - // Range of reserved numeric values. Reserved numeric values may not be used - // by enum values in the same enum declaration. Reserved ranges may not - // overlap. - repeated EnumReservedRange reserved_range = 4; - - // Reserved enum value names, which may not be reused. A given name may only - // be reserved once. - repeated string reserved_name = 5; - - // Support for `export` and `local` keywords on enums. - optional SymbolVisibility visibility = 6; -} - -// Describes a value within an enum. -message EnumValueDescriptorProto { - optional string name = 1; - optional int32 number = 2; - - optional EnumValueOptions options = 3; -} - -// Describes a service. -message ServiceDescriptorProto { - optional string name = 1; - repeated MethodDescriptorProto method = 2; - - optional ServiceOptions options = 3; - - reserved 4; - reserved "stream"; -} - -// Describes a method of a service. -message MethodDescriptorProto { - optional string name = 1; - - // Input and output type names. These are resolved in the same way as - // FieldDescriptorProto.type_name, but must refer to a message type. - optional string input_type = 2; - optional string output_type = 3; - - optional MethodOptions options = 4; - - // Identifies if client streams multiple client messages - optional bool client_streaming = 5 [default = false]; - // Identifies if server streams multiple server messages - optional bool server_streaming = 6 [default = false]; -} - -// =================================================================== -// Options - -// Each of the definitions above may have "options" attached. These are -// just annotations which may cause code to be generated slightly differently -// or may contain hints for code that manipulates protocol messages. -// -// Clients may define custom options as extensions of the *Options messages. -// These extensions may not yet be known at parsing time, so the parser cannot -// store the values in them. Instead it stores them in a field in the *Options -// message called uninterpreted_option. This field must have the same name -// across all *Options messages. We then use this field to populate the -// extensions when we build a descriptor, at which point all protos have been -// parsed and so all extensions are known. -// -// Extension numbers for custom options may be chosen as follows: -// * For options which will only be used within a single application or -// organization, or for experimental options, use field numbers 50000 -// through 99999. It is up to you to ensure that you do not use the -// same number for multiple options. -// * For options which will be published and used publicly by multiple -// independent entities, e-mail protobuf-global-extension-registry@google.com -// to reserve extension numbers. Simply provide your project name (e.g. -// Objective-C plugin) and your project website (if available) -- there's no -// need to explain how you intend to use them. Usually you only need one -// extension number. You can declare multiple options with only one extension -// number by putting them in a sub-message. See the Custom Options section of -// the docs for examples: -// https://developers.google.com/protocol-buffers/docs/proto#options -// If this turns out to be popular, a web service will be set up -// to automatically assign option numbers. - -message FileOptions { - - // Sets the Java package where classes generated from this .proto will be - // placed. By default, the proto package is used, but this is often - // inappropriate because proto packages do not normally start with backwards - // domain names. - optional string java_package = 1; - - // Controls the name of the wrapper Java class generated for the .proto file. - // That class will always contain the .proto file's getDescriptor() method as - // well as any top-level extensions defined in the .proto file. - // If java_multiple_files is disabled, then all the other classes from the - // .proto file will be nested inside the single wrapper outer class. - optional string java_outer_classname = 8; - - // If enabled, then the Java code generator will generate a separate .java - // file for each top-level message, enum, and service defined in the .proto - // file. Thus, these types will *not* be nested inside the wrapper class - // named by java_outer_classname. However, the wrapper class will still be - // generated to contain the file's getDescriptor() method as well as any - // top-level extensions defined in the file. - optional bool java_multiple_files = 10 [ - default = false, - feature_support = { - edition_introduced: EDITION_PROTO2 - edition_removed: EDITION_2024 - removal_error: "This behavior is enabled by default in editions 2024 and above. " - "To disable it, you can set `features.(pb.java).nest_in_file_class = YES` " - "on individual messages, enums, or services." - - } - ]; - - // This option does nothing. - optional bool java_generate_equals_and_hash = 20 [deprecated=true]; - - // A proto2 file can set this to true to opt in to UTF-8 checking for Java, - // which will throw an exception if invalid UTF-8 is parsed from the wire or - // assigned to a string field. - // - // TODO: clarify exactly what kinds of field types this option - // applies to, and update these docs accordingly. - // - // Proto3 files already perform these checks. Setting the option explicitly to - // false has no effect: it cannot be used to opt proto3 files out of UTF-8 - // checks. - optional bool java_string_check_utf8 = 27 [default = false]; - - // Generated classes can be optimized for speed or code size. - enum OptimizeMode { - SPEED = 1; // Generate complete code for parsing, serialization, - // etc. - CODE_SIZE = 2; // Use ReflectionOps to implement these methods. - LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. - } - optional OptimizeMode optimize_for = 9 [default = SPEED]; - - // Sets the Go package where structs generated from this .proto will be - // placed. If omitted, the Go package will be derived from the following: - // - The basename of the package import path, if provided. - // - Otherwise, the package statement in the .proto file, if present. - // - Otherwise, the basename of the .proto file, without extension. - optional string go_package = 11; - - // Should generic services be generated in each language? "Generic" services - // are not specific to any particular RPC system. They are generated by the - // main code generators in each language (without additional plugins). - // Generic services were the only kind of service generation supported by - // early versions of google.protobuf. - // - // Generic services are now considered deprecated in favor of using plugins - // that generate code specific to your particular RPC system. Therefore, - // these default to false. Old code which depends on generic services should - // explicitly set them to true. - optional bool cc_generic_services = 16 [default = false]; - optional bool java_generic_services = 17 [default = false]; - optional bool py_generic_services = 18 [default = false]; - reserved 42; // removed php_generic_services - reserved "php_generic_services"; - - // Is this file deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for everything in the file, or it will be completely ignored; in the very - // least, this is a formalization for deprecating files. - optional bool deprecated = 23 [default = false]; - - // Enables the use of arenas for the proto messages in this file. This applies - // only to generated classes for C++. - optional bool cc_enable_arenas = 31 [default = true]; - - // Sets the objective c class prefix which is prepended to all objective c - // generated classes from this .proto. There is no default. - optional string objc_class_prefix = 36; - - // Namespace for generated classes; defaults to the package. - optional string csharp_namespace = 37; - - // By default Swift generators will take the proto package and CamelCase it - // replacing '.' with underscore and use that to prefix the types/symbols - // defined. When this options is provided, they will use this value instead - // to prefix the types/symbols defined. - optional string swift_prefix = 39; - - // Sets the php class prefix which is prepended to all php generated classes - // from this .proto. Default is empty. - optional string php_class_prefix = 40; - - // Use this option to change the namespace of php generated classes. Default - // is empty. When this option is empty, the package name will be used for - // determining the namespace. - optional string php_namespace = 41; - - // Use this option to change the namespace of php generated metadata classes. - // Default is empty. When this option is empty, the proto file name will be - // used for determining the namespace. - optional string php_metadata_namespace = 44; - - // Use this option to change the package of ruby generated classes. Default - // is empty. When this option is not set, the package name will be used for - // determining the ruby package. - optional string ruby_package = 45; - - // Any features defined in the specific edition. - // WARNING: This field should only be used by protobuf plugins or special - // cases like the proto compiler. Other uses are discouraged and - // developers should rely on the protoreflect APIs for their client language. - optional FeatureSet features = 50; - - // The parser stores options it doesn't recognize here. - // See the documentation for the "Options" section above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. - // See the documentation for the "Options" section above. - extensions 1000 to max; - - reserved 38; -} - -message MessageOptions { - // Set true to use the old proto1 MessageSet wire format for extensions. - // This is provided for backwards-compatibility with the MessageSet wire - // format. You should not use this for any other reason: It's less - // efficient, has fewer features, and is more complicated. - // - // The message must be defined exactly as follows: - // message Foo { - // option message_set_wire_format = true; - // extensions 4 to max; - // } - // Note that the message cannot have any defined fields; MessageSets only - // have extensions. - // - // All extensions of your type must be singular messages; e.g. they cannot - // be int32s, enums, or repeated messages. - // - // Because this is an option, the above two restrictions are not enforced by - // the protocol compiler. - optional bool message_set_wire_format = 1 [default = false]; - - // Disables the generation of the standard "descriptor()" accessor, which can - // conflict with a field of the same name. This is meant to make migration - // from proto1 easier; new code should avoid fields named "descriptor". - optional bool no_standard_descriptor_accessor = 2 [default = false]; - - // Is this message deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the message, or it will be completely ignored; in the very least, - // this is a formalization for deprecating messages. - optional bool deprecated = 3 [default = false]; - - reserved 4, 5, 6; - - // Whether the message is an automatically generated map entry type for the - // maps field. - // - // For maps fields: - // map map_field = 1; - // The parsed descriptor looks like: - // message MapFieldEntry { - // option map_entry = true; - // optional KeyType key = 1; - // optional ValueType value = 2; - // } - // repeated MapFieldEntry map_field = 1; - // - // Implementations may choose not to generate the map_entry=true message, but - // use a native map in the target language to hold the keys and values. - // The reflection APIs in such implementations still need to work as - // if the field is a repeated message field. - // - // NOTE: Do not set the option in .proto files. Always use the maps syntax - // instead. The option should only be implicitly set by the proto compiler - // parser. - optional bool map_entry = 7; - - reserved 8; // javalite_serializable - reserved 9; // javanano_as_lite - - // Enable the legacy handling of JSON field name conflicts. This lowercases - // and strips underscored from the fields before comparison in proto3 only. - // The new behavior takes `json_name` into account and applies to proto2 as - // well. - // - // This should only be used as a temporary measure against broken builds due - // to the change in behavior for JSON field name conflicts. - // - // TODO This is legacy behavior we plan to remove once downstream - // teams have had time to migrate. - optional bool deprecated_legacy_json_field_conflicts = 11 [deprecated = true]; - - // Any features defined in the specific edition. - // WARNING: This field should only be used by protobuf plugins or special - // cases like the proto compiler. Other uses are discouraged and - // developers should rely on the protoreflect APIs for their client language. - optional FeatureSet features = 12; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message FieldOptions { - // NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead. - // The ctype option instructs the C++ code generator to use a different - // representation of the field than it normally would. See the specific - // options below. This option is only implemented to support use of - // [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of - // type "bytes" in the open source release. - // TODO: make ctype actually deprecated. - optional CType ctype = 1 [/*deprecated = true,*/ default = STRING]; - enum CType { - // Default mode. - STRING = 0; - - // The option [ctype=CORD] may be applied to a non-repeated field of type - // "bytes". It indicates that in C++, the data should be stored in a Cord - // instead of a string. For very large strings, this may reduce memory - // fragmentation. It may also allow better performance when parsing from a - // Cord, or when parsing with aliasing enabled, as the parsed Cord may then - // alias the original buffer. - CORD = 1; - - STRING_PIECE = 2; - } - // The packed option can be enabled for repeated primitive fields to enable - // a more efficient representation on the wire. Rather than repeatedly - // writing the tag and type for each element, the entire array is encoded as - // a single length-delimited blob. In proto3, only explicit setting it to - // false will avoid using packed encoding. This option is prohibited in - // Editions, but the `repeated_field_encoding` feature can be used to control - // the behavior. - optional bool packed = 2; - - // The jstype option determines the JavaScript type used for values of the - // field. The option is permitted only for 64 bit integral and fixed types - // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING - // is represented as JavaScript string, which avoids loss of precision that - // can happen when a large value is converted to a floating point JavaScript. - // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to - // use the JavaScript "number" type. The behavior of the default option - // JS_NORMAL is implementation dependent. - // - // This option is an enum to permit additional types to be added, e.g. - // goog.math.Integer. - optional JSType jstype = 6 [default = JS_NORMAL]; - enum JSType { - // Use the default type. - JS_NORMAL = 0; - - // Use JavaScript strings. - JS_STRING = 1; - - // Use JavaScript numbers. - JS_NUMBER = 2; - } - - // Should this field be parsed lazily? Lazy applies only to message-type - // fields. It means that when the outer message is initially parsed, the - // inner message's contents will not be parsed but instead stored in encoded - // form. The inner message will actually be parsed when it is first accessed. - // - // This is only a hint. Implementations are free to choose whether to use - // eager or lazy parsing regardless of the value of this option. However, - // setting this option true suggests that the protocol author believes that - // using lazy parsing on this field is worth the additional bookkeeping - // overhead typically needed to implement it. - // - // This option does not affect the public interface of any generated code; - // all method signatures remain the same. Furthermore, thread-safety of the - // interface is not affected by this option; const methods remain safe to - // call from multiple threads concurrently, while non-const methods continue - // to require exclusive access. - // - // Note that lazy message fields are still eagerly verified to check - // ill-formed wireformat or missing required fields. Calling IsInitialized() - // on the outer message would fail if the inner message has missing required - // fields. Failed verification would result in parsing failure (except when - // uninitialized messages are acceptable). - optional bool lazy = 5 [default = false]; - - // unverified_lazy does no correctness checks on the byte stream. This should - // only be used where lazy with verification is prohibitive for performance - // reasons. - optional bool unverified_lazy = 15 [default = false]; - - // Is this field deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for accessors, or it will be completely ignored; in the very least, this - // is a formalization for deprecating fields. - optional bool deprecated = 3 [default = false]; - - // DEPRECATED. DO NOT USE! - // For Google-internal migration only. Do not use. - optional bool weak = 10 [default = false, deprecated = true]; - - // Indicate that the field value should not be printed out when using debug - // formats, e.g. when the field contains sensitive credentials. - optional bool debug_redact = 16 [default = false]; - - // If set to RETENTION_SOURCE, the option will be omitted from the binary. - enum OptionRetention { - RETENTION_UNKNOWN = 0; - RETENTION_RUNTIME = 1; - RETENTION_SOURCE = 2; - } - - optional OptionRetention retention = 17; - - // This indicates the types of entities that the field may apply to when used - // as an option. If it is unset, then the field may be freely used as an - // option on any kind of entity. - enum OptionTargetType { - TARGET_TYPE_UNKNOWN = 0; - TARGET_TYPE_FILE = 1; - TARGET_TYPE_EXTENSION_RANGE = 2; - TARGET_TYPE_MESSAGE = 3; - TARGET_TYPE_FIELD = 4; - TARGET_TYPE_ONEOF = 5; - TARGET_TYPE_ENUM = 6; - TARGET_TYPE_ENUM_ENTRY = 7; - TARGET_TYPE_SERVICE = 8; - TARGET_TYPE_METHOD = 9; - } - - repeated OptionTargetType targets = 19; - - message EditionDefault { - optional Edition edition = 3; - optional string value = 2; // Textproto value. - } - repeated EditionDefault edition_defaults = 20; - - // Any features defined in the specific edition. - // WARNING: This field should only be used by protobuf plugins or special - // cases like the proto compiler. Other uses are discouraged and - // developers should rely on the protoreflect APIs for their client language. - optional FeatureSet features = 21; - - // Information about the support window of a feature. - message FeatureSupport { - // The edition that this feature was first available in. In editions - // earlier than this one, the default assigned to EDITION_LEGACY will be - // used, and proto files will not be able to override it. - optional Edition edition_introduced = 1; - - // The edition this feature becomes deprecated in. Using this after this - // edition may trigger warnings. - optional Edition edition_deprecated = 2; - - // The deprecation warning text if this feature is used after the edition it - // was marked deprecated in. - optional string deprecation_warning = 3; - - // The edition this feature is no longer available in. In editions after - // this one, the last default assigned will be used, and proto files will - // not be able to override it. - optional Edition edition_removed = 4; - - // The removal error text if this feature is used after the edition it was - // removed in. - optional string removal_error = 5; - } - optional FeatureSupport feature_support = 22; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; - - reserved 4; // removed jtype - reserved 18; // reserve target, target_obsolete_do_not_use -} - -message OneofOptions { - // Any features defined in the specific edition. - // WARNING: This field should only be used by protobuf plugins or special - // cases like the proto compiler. Other uses are discouraged and - // developers should rely on the protoreflect APIs for their client language. - optional FeatureSet features = 1; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message EnumOptions { - - // Set this option to true to allow mapping different tag names to the same - // value. - optional bool allow_alias = 2; - - // Is this enum deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum, or it will be completely ignored; in the very least, this - // is a formalization for deprecating enums. - optional bool deprecated = 3 [default = false]; - - reserved 5; // javanano_as_lite - - // Enable the legacy handling of JSON field name conflicts. This lowercases - // and strips underscored from the fields before comparison in proto3 only. - // The new behavior takes `json_name` into account and applies to proto2 as - // well. - // TODO Remove this legacy behavior once downstream teams have - // had time to migrate. - optional bool deprecated_legacy_json_field_conflicts = 6 [deprecated = true]; - - // Any features defined in the specific edition. - // WARNING: This field should only be used by protobuf plugins or special - // cases like the proto compiler. Other uses are discouraged and - // developers should rely on the protoreflect APIs for their client language. - optional FeatureSet features = 7; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message EnumValueOptions { - // Is this enum value deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum value, or it will be completely ignored; in the very least, - // this is a formalization for deprecating enum values. - optional bool deprecated = 1 [default = false]; - - // Any features defined in the specific edition. - // WARNING: This field should only be used by protobuf plugins or special - // cases like the proto compiler. Other uses are discouraged and - // developers should rely on the protoreflect APIs for their client language. - optional FeatureSet features = 2; - - // Indicate that fields annotated with this enum value should not be printed - // out when using debug formats, e.g. when the field contains sensitive - // credentials. - optional bool debug_redact = 3 [default = false]; - - // Information about the support window of a feature value. - optional FieldOptions.FeatureSupport feature_support = 4; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message ServiceOptions { - - // Any features defined in the specific edition. - // WARNING: This field should only be used by protobuf plugins or special - // cases like the proto compiler. Other uses are discouraged and - // developers should rely on the protoreflect APIs for their client language. - optional FeatureSet features = 34; - - // Note: Field numbers 1 through 32 are reserved for Google's internal RPC - // framework. We apologize for hoarding these numbers to ourselves, but - // we were already using them long before we decided to release Protocol - // Buffers. - - // Is this service deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the service, or it will be completely ignored; in the very least, - // this is a formalization for deprecating services. - optional bool deprecated = 33 [default = false]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message MethodOptions { - - // Note: Field numbers 1 through 32 are reserved for Google's internal RPC - // framework. We apologize for hoarding these numbers to ourselves, but - // we were already using them long before we decided to release Protocol - // Buffers. - - // Is this method deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the method, or it will be completely ignored; in the very least, - // this is a formalization for deprecating methods. - optional bool deprecated = 33 [default = false]; - - // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, - // or neither? HTTP based RPC implementation may choose GET verb for safe - // methods, and PUT verb for idempotent methods instead of the default POST. - enum IdempotencyLevel { - IDEMPOTENCY_UNKNOWN = 0; - NO_SIDE_EFFECTS = 1; // implies idempotent - IDEMPOTENT = 2; // idempotent, but may have side effects - } - optional IdempotencyLevel idempotency_level = 34 - [default = IDEMPOTENCY_UNKNOWN]; - - // Any features defined in the specific edition. - // WARNING: This field should only be used by protobuf plugins or special - // cases like the proto compiler. Other uses are discouraged and - // developers should rely on the protoreflect APIs for their client language. - optional FeatureSet features = 35; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -// A message representing a option the parser does not recognize. This only -// appears in options protos created by the compiler::Parser class. -// DescriptorPool resolves these when building Descriptor objects. Therefore, -// options protos in descriptor objects (e.g. returned by Descriptor::options(), -// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions -// in them. -message UninterpretedOption { - // The name of the uninterpreted option. Each string represents a segment in - // a dot-separated name. is_extension is true iff a segment represents an - // extension (denoted with parentheses in options specs in .proto files). - // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents - // "foo.(bar.baz).moo". - message NamePart { - required string name_part = 1; - required bool is_extension = 2; - } - repeated NamePart name = 2; - - // The value of the uninterpreted option, in whatever type the tokenizer - // identified it as during parsing. Exactly one of these should be set. - optional string identifier_value = 3; - optional uint64 positive_int_value = 4; - optional int64 negative_int_value = 5; - optional double double_value = 6; - optional bytes string_value = 7; - optional string aggregate_value = 8; -} - -// =================================================================== -// Features - -// TODO Enums in C++ gencode (and potentially other languages) are -// not well scoped. This means that each of the feature enums below can clash -// with each other. The short names we've chosen maximize call-site -// readability, but leave us very open to this scenario. A future feature will -// be designed and implemented to handle this, hopefully before we ever hit a -// conflict here. -message FeatureSet { - enum FieldPresence { - FIELD_PRESENCE_UNKNOWN = 0; - EXPLICIT = 1; - IMPLICIT = 2; - LEGACY_REQUIRED = 3; - } - optional FieldPresence field_presence = 1 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "EXPLICIT" }, - edition_defaults = { edition: EDITION_PROTO3, value: "IMPLICIT" }, - edition_defaults = { edition: EDITION_2023, value: "EXPLICIT" } - ]; - - enum EnumType { - ENUM_TYPE_UNKNOWN = 0; - OPEN = 1; - CLOSED = 2; - } - optional EnumType enum_type = 2 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_ENUM, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "CLOSED" }, - edition_defaults = { edition: EDITION_PROTO3, value: "OPEN" } - ]; - - enum RepeatedFieldEncoding { - REPEATED_FIELD_ENCODING_UNKNOWN = 0; - PACKED = 1; - EXPANDED = 2; - } - optional RepeatedFieldEncoding repeated_field_encoding = 3 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "EXPANDED" }, - edition_defaults = { edition: EDITION_PROTO3, value: "PACKED" } - ]; - - enum Utf8Validation { - UTF8_VALIDATION_UNKNOWN = 0; - VERIFY = 2; - NONE = 3; - reserved 1; - } - optional Utf8Validation utf8_validation = 4 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "NONE" }, - edition_defaults = { edition: EDITION_PROTO3, value: "VERIFY" } - ]; - - enum MessageEncoding { - MESSAGE_ENCODING_UNKNOWN = 0; - LENGTH_PREFIXED = 1; - DELIMITED = 2; - } - optional MessageEncoding message_encoding = 5 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "LENGTH_PREFIXED" } - ]; - - enum JsonFormat { - JSON_FORMAT_UNKNOWN = 0; - ALLOW = 1; - LEGACY_BEST_EFFORT = 2; - } - optional JsonFormat json_format = 6 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_MESSAGE, - targets = TARGET_TYPE_ENUM, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "LEGACY_BEST_EFFORT" }, - edition_defaults = { edition: EDITION_PROTO3, value: "ALLOW" } - ]; - - enum EnforceNamingStyle { - ENFORCE_NAMING_STYLE_UNKNOWN = 0; - STYLE2024 = 1; - STYLE_LEGACY = 2; - } - optional EnforceNamingStyle enforce_naming_style = 7 [ - retention = RETENTION_SOURCE, - targets = TARGET_TYPE_FILE, - targets = TARGET_TYPE_EXTENSION_RANGE, - targets = TARGET_TYPE_MESSAGE, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_ONEOF, - targets = TARGET_TYPE_ENUM, - targets = TARGET_TYPE_ENUM_ENTRY, - targets = TARGET_TYPE_SERVICE, - targets = TARGET_TYPE_METHOD, - feature_support = { - edition_introduced: EDITION_2024, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "STYLE_LEGACY" }, - edition_defaults = { edition: EDITION_2024, value: "STYLE2024" } - ]; - - message VisibilityFeature { - enum DefaultSymbolVisibility { - DEFAULT_SYMBOL_VISIBILITY_UNKNOWN = 0; - - // Default pre-EDITION_2024, all UNSET visibility are export. - EXPORT_ALL = 1; - - // All top-level symbols default to export, nested default to local. - EXPORT_TOP_LEVEL = 2; - - // All symbols default to local. - LOCAL_ALL = 3; - - // All symbols local by default. Nested types cannot be exported. - // With special case caveat for message { enum {} reserved 1 to max; } - // This is the recommended setting for new protos. - STRICT = 4; - } - reserved 1 to max; - } - optional VisibilityFeature.DefaultSymbolVisibility default_symbol_visibility = - 8 [ - retention = RETENTION_SOURCE, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2024, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "EXPORT_ALL" }, - edition_defaults = { edition: EDITION_2024, value: "EXPORT_TOP_LEVEL" } - ]; - - reserved 999; - - extensions 1000 to 9994 [ - declaration = { - number: 1000, - full_name: ".pb.cpp", - type: ".pb.CppFeatures" - }, - declaration = { - number: 1001, - full_name: ".pb.java", - type: ".pb.JavaFeatures" - }, - declaration = { number: 1002, full_name: ".pb.go", type: ".pb.GoFeatures" }, - declaration = { - number: 1003, - full_name: ".pb.python", - type: ".pb.PythonFeatures" - }, - declaration = { - number: 1100, - full_name: ".imp.impress_feature_set", - type: ".imp.ImpressFeatureSet" - }, - declaration = { - number: 9989, - full_name: ".pb.java_mutable", - type: ".pb.JavaMutableFeatures" - }, - declaration = { - number: 9990, - full_name: ".pb.proto1", - type: ".pb.Proto1Features" - } - ]; - - extensions 9995 to 9999; // For internal testing - extensions 10000; // for https://github.com/bufbuild/protobuf-es -} - -// A compiled specification for the defaults of a set of features. These -// messages are generated from FeatureSet extensions and can be used to seed -// feature resolution. The resolution with this object becomes a simple search -// for the closest matching edition, followed by proto merges. -message FeatureSetDefaults { - // A map from every known edition with a unique set of defaults to its - // defaults. Not all editions may be contained here. For a given edition, - // the defaults at the closest matching edition ordered at or before it should - // be used. This field must be in strict ascending order by edition. - message FeatureSetEditionDefault { - optional Edition edition = 3; - - // Defaults of features that can be overridden in this edition. - optional FeatureSet overridable_features = 4; - - // Defaults of features that can't be overridden in this edition. - optional FeatureSet fixed_features = 5; - - reserved 1, 2; - reserved "features"; - } - repeated FeatureSetEditionDefault defaults = 1; - - // The minimum supported edition (inclusive) when this was constructed. - // Editions before this will not have defaults. - optional Edition minimum_edition = 4; - - // The maximum known edition (inclusive) when this was constructed. Editions - // after this will not have reliable defaults. - optional Edition maximum_edition = 5; -} - -// =================================================================== -// Optional source code info - -// Encapsulates information about the original source file from which a -// FileDescriptorProto was generated. -message SourceCodeInfo { - // A Location identifies a piece of source code in a .proto file which - // corresponds to a particular definition. This information is intended - // to be useful to IDEs, code indexers, documentation generators, and similar - // tools. - // - // For example, say we have a file like: - // message Foo { - // optional string foo = 1; - // } - // Let's look at just the field definition: - // optional string foo = 1; - // ^ ^^ ^^ ^ ^^^ - // a bc de f ghi - // We have the following locations: - // span path represents - // [a,i) [ 4, 0, 2, 0 ] The whole field definition. - // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). - // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). - // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). - // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). - // - // Notes: - // - A location may refer to a repeated field itself (i.e. not to any - // particular index within it). This is used whenever a set of elements are - // logically enclosed in a single code segment. For example, an entire - // extend block (possibly containing multiple extension definitions) will - // have an outer location whose path refers to the "extensions" repeated - // field without an index. - // - Multiple locations may have the same path. This happens when a single - // logical declaration is spread out across multiple places. The most - // obvious example is the "extend" block again -- there may be multiple - // extend blocks in the same scope, each of which will have the same path. - // - A location's span is not always a subset of its parent's span. For - // example, the "extendee" of an extension declaration appears at the - // beginning of the "extend" block and is shared by all extensions within - // the block. - // - Just because a location's span is a subset of some other location's span - // does not mean that it is a descendant. For example, a "group" defines - // both a type and a field in a single declaration. Thus, the locations - // corresponding to the type and field and their components will overlap. - // - Code which tries to interpret locations should probably be designed to - // ignore those that it doesn't understand, as more types of locations could - // be recorded in the future. - repeated Location location = 1; - message Location { - // Identifies which part of the FileDescriptorProto was defined at this - // location. - // - // Each element is a field number or an index. They form a path from - // the root FileDescriptorProto to the place where the definition appears. - // For example, this path: - // [ 4, 3, 2, 7, 1 ] - // refers to: - // file.message_type(3) // 4, 3 - // .field(7) // 2, 7 - // .name() // 1 - // This is because FileDescriptorProto.message_type has field number 4: - // repeated DescriptorProto message_type = 4; - // and DescriptorProto.field has field number 2: - // repeated FieldDescriptorProto field = 2; - // and FieldDescriptorProto.name has field number 1: - // optional string name = 1; - // - // Thus, the above path gives the location of a field name. If we removed - // the last element: - // [ 4, 3, 2, 7 ] - // this path refers to the whole field declaration (from the beginning - // of the label to the terminating semicolon). - repeated int32 path = 1 [packed = true]; - - // Always has exactly three or four elements: start line, start column, - // end line (optional, otherwise assumed same as start line), end column. - // These are packed into a single field for efficiency. Note that line - // and column numbers are zero-based -- typically you will want to add - // 1 to each before displaying to a user. - repeated int32 span = 2 [packed = true]; - - // If this SourceCodeInfo represents a complete declaration, these are any - // comments appearing before and after the declaration which appear to be - // attached to the declaration. - // - // A series of line comments appearing on consecutive lines, with no other - // tokens appearing on those lines, will be treated as a single comment. - // - // leading_detached_comments will keep paragraphs of comments that appear - // before (but not connected to) the current element. Each paragraph, - // separated by empty lines, will be one comment element in the repeated - // field. - // - // Only the comment content is provided; comment markers (e.g. //) are - // stripped out. For block comments, leading whitespace and an asterisk - // will be stripped from the beginning of each line other than the first. - // Newlines are included in the output. - // - // Examples: - // - // optional int32 foo = 1; // Comment attached to foo. - // // Comment attached to bar. - // optional int32 bar = 2; - // - // optional string baz = 3; - // // Comment attached to baz. - // // Another line attached to baz. - // - // // Comment attached to moo. - // // - // // Another line attached to moo. - // optional double moo = 4; - // - // // Detached comment for corge. This is not leading or trailing comments - // // to moo or corge because there are blank lines separating it from - // // both. - // - // // Detached comment for corge paragraph 2. - // - // optional string corge = 5; - // /* Block comment attached - // * to corge. Leading asterisks - // * will be removed. */ - // /* Block comment attached to - // * grault. */ - // optional int32 grault = 6; - // - // // ignored detached comments. - optional string leading_comments = 3; - optional string trailing_comments = 4; - repeated string leading_detached_comments = 6; - } - - // Extensions for tooling. - extensions 536000000 [declaration = { - number: 536000000 - type: ".buf.descriptor.v1.SourceCodeInfoExtension" - full_name: ".buf.descriptor.v1.buf_source_code_info_extension" - }]; -} - -// Describes the relationship between generated code and its original source -// file. A GeneratedCodeInfo message is associated with only one generated -// source file, but may contain references to different source .proto files. -message GeneratedCodeInfo { - // An Annotation connects some span of text in generated code to an element - // of its generating .proto file. - repeated Annotation annotation = 1; - message Annotation { - // Identifies the element in the original source .proto file. This field - // is formatted the same as SourceCodeInfo.Location.path. - repeated int32 path = 1 [packed = true]; - - // Identifies the filesystem path to the original source .proto. - optional string source_file = 2; - - // Identifies the starting offset in bytes in the generated code - // that relates to the identified object. - optional int32 begin = 3; - - // Identifies the ending offset in bytes in the generated code that - // relates to the identified object. The end offset should be one past - // the last relevant byte (so the length of the text = end - begin). - optional int32 end = 4; - - // Represents the identified object's effect on the element in the original - // .proto file. - enum Semantic { - // There is no effect or the effect is indescribable. - NONE = 0; - // The element is set or otherwise mutated. - SET = 1; - // An alias to the element is returned. - ALIAS = 2; - } - optional Semantic semantic = 5; - } -} - -// Describes the 'visibility' of a symbol with respect to the proto import -// system. Symbols can only be imported when the visibility rules do not prevent -// it (ex: local symbols cannot be imported). Visibility modifiers can only set -// on `message` and `enum` as they are the only types available to be referenced -// from other files. -enum SymbolVisibility { - VISIBILITY_UNSET = 0; - VISIBILITY_LOCAL = 1; - VISIBILITY_EXPORT = 2; -} diff --git a/flow/proto/google/protobuf/duration.proto b/flow/proto/google/protobuf/duration.proto deleted file mode 100644 index 41f40c22247..00000000000 --- a/flow/proto/google/protobuf/duration.proto +++ /dev/null @@ -1,115 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/durationpb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "DurationProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// A Duration represents a signed, fixed-length span of time represented -// as a count of seconds and fractions of seconds at nanosecond -// resolution. It is independent of any calendar and concepts like "day" -// or "month". It is related to Timestamp in that the difference between -// two Timestamp values is a Duration and it can be added or subtracted -// from a Timestamp. Range is approximately +-10,000 years. -// -// # Examples -// -// Example 1: Compute Duration from two Timestamps in pseudo code. -// -// Timestamp start = ...; -// Timestamp end = ...; -// Duration duration = ...; -// -// duration.seconds = end.seconds - start.seconds; -// duration.nanos = end.nanos - start.nanos; -// -// if (duration.seconds < 0 && duration.nanos > 0) { -// duration.seconds += 1; -// duration.nanos -= 1000000000; -// } else if (duration.seconds > 0 && duration.nanos < 0) { -// duration.seconds -= 1; -// duration.nanos += 1000000000; -// } -// -// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. -// -// Timestamp start = ...; -// Duration duration = ...; -// Timestamp end = ...; -// -// end.seconds = start.seconds + duration.seconds; -// end.nanos = start.nanos + duration.nanos; -// -// if (end.nanos < 0) { -// end.seconds -= 1; -// end.nanos += 1000000000; -// } else if (end.nanos >= 1000000000) { -// end.seconds += 1; -// end.nanos -= 1000000000; -// } -// -// Example 3: Compute Duration from datetime.timedelta in Python. -// -// td = datetime.timedelta(days=3, minutes=10) -// duration = Duration() -// duration.FromTimedelta(td) -// -// # JSON Mapping -// -// In JSON format, the Duration type is encoded as a string rather than an -// object, where the string ends in the suffix "s" (indicating seconds) and -// is preceded by the number of seconds, with nanoseconds expressed as -// fractional seconds. For example, 3 seconds with 0 nanoseconds should be -// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should -// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 -// microsecond should be expressed in JSON format as "3.000001s". -// -message Duration { - // Signed seconds of the span of time. Must be from -315,576,000,000 - // to +315,576,000,000 inclusive. Note: these bounds are computed from: - // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years - int64 seconds = 1; - - // Signed fractions of a second at nanosecond resolution of the span - // of time. Durations less than one second are represented with a 0 - // `seconds` field and a positive or negative `nanos` field. For durations - // of one second or more, a non-zero value for the `nanos` field must be - // of the same sign as the `seconds` field. Must be from -999,999,999 - // to +999,999,999 inclusive. - int32 nanos = 2; -} diff --git a/flow/proto/google/protobuf/empty.proto b/flow/proto/google/protobuf/empty.proto deleted file mode 100644 index b87c89dcfce..00000000000 --- a/flow/proto/google/protobuf/empty.proto +++ /dev/null @@ -1,51 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option go_package = "google.golang.org/protobuf/types/known/emptypb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "EmptyProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option cc_enable_arenas = true; - -// A generic empty message that you can re-use to avoid defining duplicated -// empty messages in your APIs. A typical example is to use it as the request -// or the response type of an API method. For instance: -// -// service Foo { -// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); -// } -// -message Empty {} diff --git a/flow/proto/google/protobuf/field_mask.proto b/flow/proto/google/protobuf/field_mask.proto deleted file mode 100644 index 7093fba50dd..00000000000 --- a/flow/proto/google/protobuf/field_mask.proto +++ /dev/null @@ -1,243 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "FieldMaskProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; -option cc_enable_arenas = true; - -// `FieldMask` represents a set of symbolic field paths, for example: -// -// paths: "f.a" -// paths: "f.b.d" -// -// Here `f` represents a field in some root message, `a` and `b` -// fields in the message found in `f`, and `d` a field found in the -// message in `f.b`. -// -// Field masks are used to specify a subset of fields that should be -// returned by a get operation or modified by an update operation. -// Field masks also have a custom JSON encoding (see below). -// -// # Field Masks in Projections -// -// When used in the context of a projection, a response message or -// sub-message is filtered by the API to only contain those fields as -// specified in the mask. For example, if the mask in the previous -// example is applied to a response message as follows: -// -// f { -// a : 22 -// b { -// d : 1 -// x : 2 -// } -// y : 13 -// } -// z: 8 -// -// The result will not contain specific values for fields x,y and z -// (their value will be set to the default, and omitted in proto text -// output): -// -// -// f { -// a : 22 -// b { -// d : 1 -// } -// } -// -// A repeated field is not allowed except at the last position of a -// paths string. -// -// If a FieldMask object is not present in a get operation, the -// operation applies to all fields (as if a FieldMask of all fields -// had been specified). -// -// Note that a field mask does not necessarily apply to the -// top-level response message. In case of a REST get operation, the -// field mask applies directly to the response, but in case of a REST -// list operation, the mask instead applies to each individual message -// in the returned resource list. In case of a REST custom method, -// other definitions may be used. Where the mask applies will be -// clearly documented together with its declaration in the API. In -// any case, the effect on the returned resource/resources is required -// behavior for APIs. -// -// # Field Masks in Update Operations -// -// A field mask in update operations specifies which fields of the -// targeted resource are going to be updated. The API is required -// to only change the values of the fields as specified in the mask -// and leave the others untouched. If a resource is passed in to -// describe the updated values, the API ignores the values of all -// fields not covered by the mask. -// -// If a repeated field is specified for an update operation, new values will -// be appended to the existing repeated field in the target resource. Note that -// a repeated field is only allowed in the last position of a `paths` string. -// -// If a sub-message is specified in the last position of the field mask for an -// update operation, then new value will be merged into the existing sub-message -// in the target resource. -// -// For example, given the target message: -// -// f { -// b { -// d: 1 -// x: 2 -// } -// c: [1] -// } -// -// And an update message: -// -// f { -// b { -// d: 10 -// } -// c: [2] -// } -// -// then if the field mask is: -// -// paths: ["f.b", "f.c"] -// -// then the result will be: -// -// f { -// b { -// d: 10 -// x: 2 -// } -// c: [1, 2] -// } -// -// An implementation may provide options to override this default behavior for -// repeated and message fields. -// -// Note that libraries which implement FieldMask resolution have various -// different behaviors in the face of empty masks or the special "*" mask. -// When implementing a service you should confirm these cases have the -// appropriate behavior in the underlying FieldMask library that you desire, -// and you may need to special case those cases in your application code if -// the underlying field mask library behavior differs from your intended -// service semantics. -// -// Update methods implementing https://google.aip.dev/134 -// - MUST support the special value * meaning "full replace" -// - MUST treat an omitted field mask as "replace fields which are present". -// -// Other methods implementing https://google.aip.dev/157 -// - SHOULD support the special value "*" to mean "get all". -// - MUST treat an omitted field mask to mean "get all", unless otherwise -// documented. -// -// ## Considerations for HTTP REST -// -// The HTTP kind of an update operation which uses a field mask must -// be set to PATCH instead of PUT in order to satisfy HTTP semantics -// (PUT must only be used for full updates). -// -// # JSON Encoding of Field Masks -// -// In JSON, a field mask is encoded as a single string where paths are -// separated by a comma. Fields name in each path are converted -// to/from lower-camel naming conventions. -// -// As an example, consider the following message declarations: -// -// message Profile { -// User user = 1; -// Photo photo = 2; -// } -// message User { -// string display_name = 1; -// string address = 2; -// } -// -// In proto a field mask for `Profile` may look as such: -// -// mask { -// paths: "user.display_name" -// paths: "photo" -// } -// -// In JSON, the same mask is represented as below: -// -// { -// mask: "user.displayName,photo" -// } -// -// # Field Masks and Oneof Fields -// -// Field masks treat fields in oneofs just as regular fields. Consider the -// following message: -// -// message SampleMessage { -// oneof test_oneof { -// string name = 4; -// SubMessage sub_message = 9; -// } -// } -// -// The field mask can be: -// -// mask { -// paths: "name" -// } -// -// Or: -// -// mask { -// paths: "sub_message" -// } -// -// Note that oneof type names ("test_oneof" in this case) cannot be used in -// paths. -// -// ## Field Mask Verification -// -// The implementation of any API method which has a FieldMask type field in the -// request should verify the included field paths, and return an -// `INVALID_ARGUMENT` error if any path is unmappable. -message FieldMask { - // The set of field mask paths. - repeated string paths = 1; -} diff --git a/flow/proto/google/protobuf/go_features.proto b/flow/proto/google/protobuf/go_features.proto deleted file mode 100644 index 13819acd3b4..00000000000 --- a/flow/proto/google/protobuf/go_features.proto +++ /dev/null @@ -1,112 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2023 Google Inc. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -syntax = "proto2"; - -package pb; - -import "google/protobuf/descriptor.proto"; - -option go_package = "google.golang.org/protobuf/types/gofeaturespb"; - -extend google.protobuf.FeatureSet { - optional GoFeatures go = 1002; -} - -message GoFeatures { - // Whether or not to generate the deprecated UnmarshalJSON method for enums. - // Can only be true for proto using the Open Struct api. - optional bool legacy_unmarshal_json_enum = 1 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_ENUM, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - edition_deprecated: EDITION_2023, - deprecation_warning: "The legacy UnmarshalJSON API is deprecated and " - "will be removed in a future edition.", - }, - edition_defaults = { edition: EDITION_LEGACY, value: "true" }, - edition_defaults = { edition: EDITION_PROTO3, value: "false" } - ]; - - enum APILevel { - // API_LEVEL_UNSPECIFIED results in selecting the OPEN API, - // but needs to be a separate value to distinguish between - // an explicitly set api level or a missing api level. - API_LEVEL_UNSPECIFIED = 0; - API_OPEN = 1; - API_HYBRID = 2; - API_OPAQUE = 3; - } - - // One of OPEN, HYBRID or OPAQUE. - optional APILevel api_level = 2 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_MESSAGE, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - }, - edition_defaults = { - edition: EDITION_LEGACY, - value: "API_LEVEL_UNSPECIFIED" - }, - edition_defaults = { edition: EDITION_2024, value: "API_OPAQUE" } - ]; - - enum StripEnumPrefix { - STRIP_ENUM_PREFIX_UNSPECIFIED = 0; - STRIP_ENUM_PREFIX_KEEP = 1; - STRIP_ENUM_PREFIX_GENERATE_BOTH = 2; - STRIP_ENUM_PREFIX_STRIP = 3; - } - - optional StripEnumPrefix strip_enum_prefix = 3 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_ENUM, - targets = TARGET_TYPE_ENUM_ENTRY, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2024, - }, - // TODO: change the default to STRIP_ENUM_PREFIX_STRIP for edition 2025. - edition_defaults = { - edition: EDITION_LEGACY, - value: "STRIP_ENUM_PREFIX_KEEP" - } - ]; - - // Wrap the OptimizeMode enum in a message for scoping: - // This way, users can type shorter names (SPEED, CODE_SIZE). - message OptimizeModeFeature { - // The name of this enum matches OptimizeMode in descriptor.proto. - enum OptimizeMode { - // OPTIMIZE_MODE_UNSPECIFIED results in falling back to the default - // (optimize for code size), but needs to be a separate value to distinguish - // between an explicitly set optimize mode or a missing optimize mode. - OPTIMIZE_MODE_UNSPECIFIED = 0; - SPEED = 1; - CODE_SIZE = 2; - // There is no enum entry for LITE_RUNTIME (descriptor.proto), - // because Go Protobuf does not have the concept of a lite runtime. - } - } - - optional OptimizeModeFeature.OptimizeMode optimize_mode = 4 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_MESSAGE, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2024, - }, - edition_defaults = { - edition: EDITION_LEGACY, - value: "OPTIMIZE_MODE_UNSPECIFIED" - } - ]; -} diff --git a/flow/proto/google/protobuf/java_features.proto b/flow/proto/google/protobuf/java_features.proto deleted file mode 100644 index 80ac6fa9f11..00000000000 --- a/flow/proto/google/protobuf/java_features.proto +++ /dev/null @@ -1,132 +0,0 @@ - -// Protocol Buffers - Google's data interchange format -// Copyright 2023 Google Inc. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -syntax = "proto2"; - -package pb; - -import "google/protobuf/descriptor.proto"; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "JavaFeaturesProto"; - -extend google.protobuf.FeatureSet { - optional JavaFeatures java = 1001; -} - -message JavaFeatures { - // Whether or not to treat an enum field as closed. This option is only - // applicable to enum fields, and will be removed in the future. It is - // consistent with the legacy behavior of using proto3 enum types for proto2 - // fields. - optional bool legacy_closed_enum = 1 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - edition_deprecated: EDITION_2023, - deprecation_warning: "The legacy closed enum behavior in Java is " - "deprecated and is scheduled to be removed in " - "edition 2025. See http://protobuf.dev/programming-guides/enum/#java for " - "more information.", - }, - edition_defaults = { edition: EDITION_LEGACY, value: "true" }, - edition_defaults = { edition: EDITION_PROTO3, value: "false" } - ]; - - // The UTF8 validation strategy to use. - enum Utf8Validation { - // Invalid default, which should never be used. - UTF8_VALIDATION_UNKNOWN = 0; - // Respect the UTF8 validation behavior specified by the global - // utf8_validation feature. - DEFAULT = 1; - // Verifies UTF8 validity overriding the global utf8_validation - // feature. This represents the legacy java_string_check_utf8 option. - VERIFY = 2; - } - optional Utf8Validation utf8_validation = 2 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FIELD, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2023, - edition_deprecated: EDITION_2024, - deprecation_warning: "The Java-specific utf8 validation feature is " - "deprecated and is scheduled to be removed in " - "edition 2025. Utf8 validation behavior should " - "use the global cross-language utf8_validation " - "feature.", - }, - edition_defaults = { edition: EDITION_LEGACY, value: "DEFAULT" } - ]; - - // Allows creation of large Java enums, extending beyond the standard - // constant limits imposed by the Java language. - optional bool large_enum = 3 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_ENUM, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2024, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "false" } - ]; - - // Whether to use the old default outer class name scheme, or the new feature - // which adds a "Proto" suffix to the outer class name. - // - // Users will not be able to set this option, because we removed it in the - // same edition that it was introduced. But we use it to determine which - // naming scheme to use for outer class name defaults. - optional bool use_old_outer_classname_default = 4 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_FILE, - feature_support = { - edition_introduced: EDITION_2024, - edition_removed: EDITION_2024, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "true" }, - edition_defaults = { edition: EDITION_2024, value: "false" } - ]; - - message NestInFileClassFeature { - enum NestInFileClass { - // Invalid default, which should never be used. - NEST_IN_FILE_CLASS_UNKNOWN = 0; - // Do not nest the generated class in the file class. - NO = 1; - // Nest the generated class in the file class. - YES = 2; - // Fall back to the `java_multiple_files` option. Users won't be able to - // set this option. - LEGACY = 3 [feature_support = { - edition_introduced: EDITION_2024 - edition_removed: EDITION_2024 - }]; - } - reserved 1 to max; - } - - // Whether to nest the generated class in the generated file class. This is - // only applicable to *top-level* messages, enums, and services. - optional NestInFileClassFeature.NestInFileClass nest_in_file_class = 5 [ - retention = RETENTION_RUNTIME, - targets = TARGET_TYPE_MESSAGE, - targets = TARGET_TYPE_ENUM, - targets = TARGET_TYPE_SERVICE, - feature_support = { - edition_introduced: EDITION_2024, - }, - edition_defaults = { edition: EDITION_LEGACY, value: "LEGACY" }, - edition_defaults = { edition: EDITION_2024, value: "NO" } - ]; - - reserved 6; // field `mutable_nest_in_file_class` removed. -} diff --git a/flow/proto/google/protobuf/source_context.proto b/flow/proto/google/protobuf/source_context.proto deleted file mode 100644 index 135f50fea51..00000000000 --- a/flow/proto/google/protobuf/source_context.proto +++ /dev/null @@ -1,48 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "SourceContextProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; - -// `SourceContext` represents information about the source of a -// protobuf element, like the file in which it is defined. -message SourceContext { - // The path-qualified name of the .proto file that contained the associated - // protobuf element. For example: `"google/protobuf/source_context.proto"`. - string file_name = 1; -} diff --git a/flow/proto/google/protobuf/struct.proto b/flow/proto/google/protobuf/struct.proto deleted file mode 100644 index 1bf0c1ad958..00000000000 --- a/flow/proto/google/protobuf/struct.proto +++ /dev/null @@ -1,95 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/structpb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "StructProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// `Struct` represents a structured data value, consisting of fields -// which map to dynamically typed values. In some languages, `Struct` -// might be supported by a native representation. For example, in -// scripting languages like JS a struct is represented as an -// object. The details of that representation are described together -// with the proto support for the language. -// -// The JSON representation for `Struct` is JSON object. -message Struct { - // Unordered map of dynamically typed values. - map fields = 1; -} - -// `Value` represents a dynamically typed value which can be either -// null, a number, a string, a boolean, a recursive struct value, or a -// list of values. A producer of value is expected to set one of these -// variants. Absence of any variant indicates an error. -// -// The JSON representation for `Value` is JSON value. -message Value { - // The kind of value. - oneof kind { - // Represents a null value. - NullValue null_value = 1; - // Represents a double value. - double number_value = 2; - // Represents a string value. - string string_value = 3; - // Represents a boolean value. - bool bool_value = 4; - // Represents a structured value. - Struct struct_value = 5; - // Represents a repeated `Value`. - ListValue list_value = 6; - } -} - -// `NullValue` is a singleton enumeration to represent the null value for the -// `Value` type union. -// -// The JSON representation for `NullValue` is JSON `null`. -enum NullValue { - // Null value. - NULL_VALUE = 0; -} - -// `ListValue` is a wrapper around a repeated field of values. -// -// The JSON representation for `ListValue` is JSON array. -message ListValue { - // Repeated field of dynamically typed values. - repeated Value values = 1; -} diff --git a/flow/proto/google/protobuf/timestamp.proto b/flow/proto/google/protobuf/timestamp.proto deleted file mode 100644 index 6bc1efc6d60..00000000000 --- a/flow/proto/google/protobuf/timestamp.proto +++ /dev/null @@ -1,145 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/timestamppb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "TimestampProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// A Timestamp represents a point in time independent of any time zone or local -// calendar, encoded as a count of seconds and fractions of seconds at -// nanosecond resolution. The count is relative to an epoch at UTC midnight on -// January 1, 1970, in the proleptic Gregorian calendar which extends the -// Gregorian calendar backwards to year one. -// -// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap -// second table is needed for interpretation, using a [24-hour linear -// smear](https://developers.google.com/time/smear). -// -// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By -// restricting to that range, we ensure that we can convert to and from [RFC -// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. -// -// # Examples -// -// Example 1: Compute Timestamp from POSIX `time()`. -// -// Timestamp timestamp; -// timestamp.set_seconds(time(NULL)); -// timestamp.set_nanos(0); -// -// Example 2: Compute Timestamp from POSIX `gettimeofday()`. -// -// struct timeval tv; -// gettimeofday(&tv, NULL); -// -// Timestamp timestamp; -// timestamp.set_seconds(tv.tv_sec); -// timestamp.set_nanos(tv.tv_usec * 1000); -// -// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. -// -// FILETIME ft; -// GetSystemTimeAsFileTime(&ft); -// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; -// -// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z -// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. -// Timestamp timestamp; -// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); -// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); -// -// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. -// -// long millis = System.currentTimeMillis(); -// -// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) -// .setNanos((int) ((millis % 1000) * 1000000)).build(); -// -// Example 5: Compute Timestamp from Java `Instant.now()`. -// -// Instant now = Instant.now(); -// -// Timestamp timestamp = -// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) -// .setNanos(now.getNano()).build(); -// -// Example 6: Compute Timestamp from current time in Python. -// -// timestamp = Timestamp() -// timestamp.GetCurrentTime() -// -// # JSON Mapping -// -// In JSON format, the Timestamp type is encoded as a string in the -// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the -// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" -// where {year} is always expressed using four digits while {month}, {day}, -// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional -// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), -// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone -// is required. A ProtoJSON serializer should always use UTC (as indicated by -// "Z") when printing the Timestamp type and a ProtoJSON parser should be -// able to accept both UTC and other timezones (as indicated by an offset). -// -// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past -// 01:30 UTC on January 15, 2017. -// -// In JavaScript, one can convert a Date object to this format using the -// standard -// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) -// method. In Python, a standard `datetime.datetime` object can be converted -// to this format using -// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with -// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use -// the Joda Time's [`ISODateTimeFormat.dateTime()`]( -// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime() -// ) to obtain a formatter capable of generating timestamps in this format. -// -message Timestamp { - // Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must - // be between -62135596800 and 253402300799 inclusive (which corresponds to - // 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z). - int64 seconds = 1; - - // Non-negative fractions of a second at nanosecond resolution. This field is - // the nanosecond portion of the duration, not an alternative to seconds. - // Negative second values with fractions must still have non-negative nanos - // values that count forward in time. Must be between 0 and 999,999,999 - // inclusive. - int32 nanos = 2; -} diff --git a/flow/proto/google/protobuf/type.proto b/flow/proto/google/protobuf/type.proto deleted file mode 100644 index 2c7615ed6d3..00000000000 --- a/flow/proto/google/protobuf/type.proto +++ /dev/null @@ -1,217 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -import "google/protobuf/any.proto"; -import "google/protobuf/source_context.proto"; - -option cc_enable_arenas = true; -option java_package = "com.google.protobuf"; -option java_outer_classname = "TypeProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/typepb"; - -// A protocol buffer message type. -// -// New usages of this message as an alternative to DescriptorProto are strongly -// discouraged. This message does not reliability preserve all information -// necessary to model the schema and preserve semantics. Instead make use of -// FileDescriptorSet which preserves the necessary information. -message Type { - // The fully qualified message name. - string name = 1; - // The list of fields. - repeated Field fields = 2; - // The list of types appearing in `oneof` definitions in this type. - repeated string oneofs = 3; - // The protocol buffer options. - repeated Option options = 4; - // The source context. - SourceContext source_context = 5; - // The source syntax. - Syntax syntax = 6; - // The source edition string, only valid when syntax is SYNTAX_EDITIONS. - string edition = 7; -} - -// A single field of a message type. -// -// New usages of this message as an alternative to FieldDescriptorProto are -// strongly discouraged. This message does not reliability preserve all -// information necessary to model the schema and preserve semantics. Instead -// make use of FileDescriptorSet which preserves the necessary information. -message Field { - // Basic field types. - enum Kind { - // Field type unknown. - TYPE_UNKNOWN = 0; - // Field type double. - TYPE_DOUBLE = 1; - // Field type float. - TYPE_FLOAT = 2; - // Field type int64. - TYPE_INT64 = 3; - // Field type uint64. - TYPE_UINT64 = 4; - // Field type int32. - TYPE_INT32 = 5; - // Field type fixed64. - TYPE_FIXED64 = 6; - // Field type fixed32. - TYPE_FIXED32 = 7; - // Field type bool. - TYPE_BOOL = 8; - // Field type string. - TYPE_STRING = 9; - // Field type group. Proto2 syntax only, and deprecated. - TYPE_GROUP = 10; - // Field type message. - TYPE_MESSAGE = 11; - // Field type bytes. - TYPE_BYTES = 12; - // Field type uint32. - TYPE_UINT32 = 13; - // Field type enum. - TYPE_ENUM = 14; - // Field type sfixed32. - TYPE_SFIXED32 = 15; - // Field type sfixed64. - TYPE_SFIXED64 = 16; - // Field type sint32. - TYPE_SINT32 = 17; - // Field type sint64. - TYPE_SINT64 = 18; - } - - // Whether a field is optional, required, or repeated. - enum Cardinality { - // For fields with unknown cardinality. - CARDINALITY_UNKNOWN = 0; - // For optional fields. - CARDINALITY_OPTIONAL = 1; - // For required fields. Proto2 syntax only. - CARDINALITY_REQUIRED = 2; - // For repeated fields. - CARDINALITY_REPEATED = 3; - } - - // The field type. - Kind kind = 1; - // The field cardinality. - Cardinality cardinality = 2; - // The field number. - int32 number = 3; - // The field name. - string name = 4; - // The field type URL, without the scheme, for message or enumeration - // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. - string type_url = 6; - // The index of the field type in `Type.oneofs`, for message or enumeration - // types. The first type has index 1; zero means the type is not in the list. - int32 oneof_index = 7; - // Whether to use alternative packed wire representation. - bool packed = 8; - // The protocol buffer options. - repeated Option options = 9; - // The field JSON name. - string json_name = 10; - // The string value of the default value of this field. Proto2 syntax only. - string default_value = 11; -} - -// Enum type definition. -// -// New usages of this message as an alternative to EnumDescriptorProto are -// strongly discouraged. This message does not reliability preserve all -// information necessary to model the schema and preserve semantics. Instead -// make use of FileDescriptorSet which preserves the necessary information. -message Enum { - // Enum type name. - string name = 1; - // Enum value definitions. - repeated EnumValue enumvalue = 2; - // Protocol buffer options. - repeated Option options = 3; - // The source context. - SourceContext source_context = 4; - // The source syntax. - Syntax syntax = 5; - // The source edition string, only valid when syntax is SYNTAX_EDITIONS. - string edition = 6; -} - -// Enum value definition. -// -// New usages of this message as an alternative to EnumValueDescriptorProto are -// strongly discouraged. This message does not reliability preserve all -// information necessary to model the schema and preserve semantics. Instead -// make use of FileDescriptorSet which preserves the necessary information. -message EnumValue { - // Enum value name. - string name = 1; - // Enum value number. - int32 number = 2; - // Protocol buffer options. - repeated Option options = 3; -} - -// A protocol buffer option, which can be attached to a message, field, -// enumeration, etc. -// -// New usages of this message as an alternative to FileOptions, MessageOptions, -// FieldOptions, EnumOptions, EnumValueOptions, ServiceOptions, or MethodOptions -// are strongly discouraged. -message Option { - // The option's name. For protobuf built-in options (options defined in - // descriptor.proto), this is the short name. For example, `"map_entry"`. - // For custom options, it should be the fully-qualified name. For example, - // `"google.api.http"`. - string name = 1; - // The option's value packed in an Any message. If the value is a primitive, - // the corresponding wrapper type defined in google/protobuf/wrappers.proto - // should be used. If the value is an enum, it should be stored as an int32 - // value using the google.protobuf.Int32Value type. - Any value = 2; -} - -// The syntax in which a protocol buffer element is defined. -enum Syntax { - // Syntax `proto2`. - SYNTAX_PROTO2 = 0; - // Syntax `proto3`. - SYNTAX_PROTO3 = 1; - // Syntax `editions`. - SYNTAX_EDITIONS = 2; -} diff --git a/flow/proto/google/protobuf/wrappers.proto b/flow/proto/google/protobuf/wrappers.proto deleted file mode 100644 index e583e7c40be..00000000000 --- a/flow/proto/google/protobuf/wrappers.proto +++ /dev/null @@ -1,157 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Wrappers for primitive (non-message) types. These types were needed -// for legacy reasons and are not recommended for use in new APIs. -// -// Historically these wrappers were useful to have presence on proto3 primitive -// fields, but proto3 syntax has been updated to support the `optional` keyword. -// Using that keyword is now the strongly preferred way to add presence to -// proto3 primitive fields. -// -// A secondary usecase was to embed primitives in the `google.protobuf.Any` -// type: it is now recommended that you embed your value in your own wrapper -// message which can be specifically documented. -// -// These wrappers have no meaningful use within repeated fields as they lack -// the ability to detect presence on individual elements. -// These wrappers have no meaningful use within a map or a oneof since -// individual entries of a map or fields of a oneof can already detect presence. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "WrappersProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// Wrapper message for `double`. -// -// The JSON representation for `DoubleValue` is JSON number. -// -// Not recommended for use in new APIs, but still useful for legacy APIs and -// has no plan to be removed. -message DoubleValue { - // The double value. - double value = 1; -} - -// Wrapper message for `float`. -// -// The JSON representation for `FloatValue` is JSON number. -// -// Not recommended for use in new APIs, but still useful for legacy APIs and -// has no plan to be removed. -message FloatValue { - // The float value. - float value = 1; -} - -// Wrapper message for `int64`. -// -// The JSON representation for `Int64Value` is JSON string. -// -// Not recommended for use in new APIs, but still useful for legacy APIs and -// has no plan to be removed. -message Int64Value { - // The int64 value. - int64 value = 1; -} - -// Wrapper message for `uint64`. -// -// The JSON representation for `UInt64Value` is JSON string. -// -// Not recommended for use in new APIs, but still useful for legacy APIs and -// has no plan to be removed. -message UInt64Value { - // The uint64 value. - uint64 value = 1; -} - -// Wrapper message for `int32`. -// -// The JSON representation for `Int32Value` is JSON number. -// -// Not recommended for use in new APIs, but still useful for legacy APIs and -// has no plan to be removed. -message Int32Value { - // The int32 value. - int32 value = 1; -} - -// Wrapper message for `uint32`. -// -// The JSON representation for `UInt32Value` is JSON number. -// -// Not recommended for use in new APIs, but still useful for legacy APIs and -// has no plan to be removed. -message UInt32Value { - // The uint32 value. - uint32 value = 1; -} - -// Wrapper message for `bool`. -// -// The JSON representation for `BoolValue` is JSON `true` and `false`. -// -// Not recommended for use in new APIs, but still useful for legacy APIs and -// has no plan to be removed. -message BoolValue { - // The bool value. - bool value = 1; -} - -// Wrapper message for `string`. -// -// The JSON representation for `StringValue` is JSON string. -// -// Not recommended for use in new APIs, but still useful for legacy APIs and -// has no plan to be removed. -message StringValue { - // The string value. - string value = 1; -} - -// Wrapper message for `bytes`. -// -// The JSON representation for `BytesValue` is JSON string. -// -// Not recommended for use in new APIs, but still useful for legacy APIs and -// has no plan to be removed. -message BytesValue { - // The bytes value. - bytes value = 1; -} From d9d585e1d436b1500faff8f8b3658a3a13b09401 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Thu, 11 Jun 2026 12:19:58 +0200 Subject: [PATCH 09/30] pacifying linter Signed-off-by: Dmitri --- client/internal/netflow/manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/internal/netflow/manager.go b/client/internal/netflow/manager.go index 869bddb7a62..f492098d266 100644 --- a/client/internal/netflow/manager.go +++ b/client/internal/netflow/manager.go @@ -273,7 +273,7 @@ func (m *Manager) startRetries(ctx context.Context) { continue } if err := m.send(e); err != nil { - ticker = time.NewTimer(retryBackoff.NextBackOff()) //nolint:staticcheck + ticker = time.NewTimer(retryBackoff.NextBackOff()) //nolint:staticcheck,wastedassign break } } From 98ce097ecbd37bb4e738bf08064769bbc06f35cd Mon Sep 17 00:00:00 2001 From: Dmitri Date: Thu, 11 Jun 2026 15:34:03 +0200 Subject: [PATCH 10/30] update test to validate event aggregation over tcp, udp, icmp, and icmpv6 Signed-off-by: Dmitri --- .../netflow/store/tcp_aggregation_test.go | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/client/internal/netflow/store/tcp_aggregation_test.go b/client/internal/netflow/store/tcp_aggregation_test.go index 4d28c454fcb..a4c9eab95ee 100644 --- a/client/internal/netflow/store/tcp_aggregation_test.go +++ b/client/internal/netflow/store/tcp_aggregation_test.go @@ -18,7 +18,8 @@ var pregeneratedUUIDs = func() []uuid.UUID { return toret }() -func TestTcpAggregation(t *testing.T) { +func TestFlowAggregation(t *testing.T) { + var protocols = []types.Protocol{types.ICMP, types.ICMPv6, types.TCP, types.UDP} var tests = []struct { description string events []*types.Event @@ -35,7 +36,6 @@ func TestTcpAggregation(t *testing.T) { Type: types.TypeStart, RuleID: []byte("rule-id-1"), Direction: types.Egress, - Protocol: types.TCP, SourceIP: ipAddr("1.1.1.1"), SourcePort: 1234, DestIP: ipAddr("2.2.2.2"), @@ -55,7 +55,6 @@ func TestTcpAggregation(t *testing.T) { Type: types.TypeEnd, RuleID: []byte("rule-id-1"), Direction: types.Egress, - Protocol: types.TCP, SourceIP: ipAddr("1.1.1.1"), SourcePort: 1234, DestIP: ipAddr("2.2.2.2"), @@ -77,7 +76,6 @@ func TestTcpAggregation(t *testing.T) { Type: types.TypeStart, RuleID: []byte("rule-id-1"), Direction: types.Egress, - Protocol: types.TCP, SourceIP: ipAddr("1.1.1.1"), SourcePort: 1234, DestIP: ipAddr("2.2.2.2"), @@ -105,7 +103,6 @@ func TestTcpAggregation(t *testing.T) { Type: types.TypeStart, RuleID: []byte("rule-id-1"), Direction: types.Egress, - Protocol: types.TCP, SourceIP: ipAddr("1.1.1.1"), SourcePort: 1234, DestIP: ipAddr("2.2.2.2"), @@ -125,7 +122,6 @@ func TestTcpAggregation(t *testing.T) { Type: types.TypeDrop, RuleID: []byte("rule-id-1"), Direction: types.Egress, - Protocol: types.TCP, SourceIP: ipAddr("1.1.1.1"), SourcePort: 1234, DestIP: ipAddr("2.2.2.2"), @@ -147,7 +143,6 @@ func TestTcpAggregation(t *testing.T) { Type: types.TypeStart, RuleID: []byte("rule-id-1"), Direction: types.Egress, - Protocol: types.TCP, SourceIP: ipAddr("1.1.1.1"), SourcePort: 1234, DestIP: ipAddr("2.2.2.2"), @@ -175,7 +170,6 @@ func TestTcpAggregation(t *testing.T) { Type: types.TypeStart, RuleID: []byte("rule-id-1"), Direction: types.Egress, - Protocol: types.TCP, SourceIP: ipAddr("1.1.1.1"), SourcePort: 1234, DestIP: ipAddr("2.2.2.2"), @@ -197,7 +191,6 @@ func TestTcpAggregation(t *testing.T) { Type: types.TypeStart, RuleID: []byte("rule-id-1"), Direction: types.Egress, - Protocol: types.TCP, SourceIP: ipAddr("1.1.1.1"), SourcePort: 1234, DestIP: ipAddr("2.2.2.2"), @@ -225,7 +218,6 @@ func TestTcpAggregation(t *testing.T) { Type: types.TypeDrop, RuleID: []byte("rule-id-1"), Direction: types.Egress, - Protocol: types.TCP, SourceIP: ipAddr("1.1.1.1"), SourcePort: 1234, DestIP: ipAddr("2.2.2.2"), @@ -247,7 +239,6 @@ func TestTcpAggregation(t *testing.T) { Type: types.TypeDrop, RuleID: []byte("rule-id-1"), Direction: types.Egress, - Protocol: types.TCP, SourceIP: ipAddr("1.1.1.1"), SourcePort: 1234, DestIP: ipAddr("2.2.2.2"), @@ -265,16 +256,22 @@ func TestTcpAggregation(t *testing.T) { }, }} - for _, tt := range tests { - t.Run(tt.description, func(t *testing.T) { - store := NewAggregatingMemoryStore() - for _, e := range tt.events { - store.StoreEvent(e) - } - events := store.GetAggregatedEvents() - assert.Len(t, events, len(tt.expected)) - assert.ElementsMatch(t, events, tt.expected) - }) + for _, protocol := range protocols { + for _, tt := range tests { + t.Run(tt.description+" "+protocol.String(), func(t *testing.T) { + store := NewAggregatingMemoryStore() + for _, e := range tt.events { + e.Protocol = protocol + store.StoreEvent(e) + } + for _, e := range tt.expected { + e.Protocol = protocol + } + events := store.GetAggregatedEvents() + assert.Len(t, events, len(tt.expected)) + assert.ElementsMatch(t, events, tt.expected) + }) + } } } From b21f7f7d6a564ad383b9a8d9565849e3584ac053 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Fri, 12 Jun 2026 15:14:17 +0200 Subject: [PATCH 11/30] updated event aggregation test Signed-off-by: Dmitri --- .../netflow/store/event_aggregation_test.go | 190 ++++++++++++ client/internal/netflow/store/memory.go | 2 +- .../netflow/store/tcp_aggregation_test.go | 281 ------------------ 3 files changed, 191 insertions(+), 282 deletions(-) create mode 100644 client/internal/netflow/store/event_aggregation_test.go delete mode 100644 client/internal/netflow/store/tcp_aggregation_test.go diff --git a/client/internal/netflow/store/event_aggregation_test.go b/client/internal/netflow/store/event_aggregation_test.go new file mode 100644 index 00000000000..a0fe8ef8e45 --- /dev/null +++ b/client/internal/netflow/store/event_aggregation_test.go @@ -0,0 +1,190 @@ +package store + +import ( + "math/rand" + "net/netip" + "testing" + "time" + + "github.com/google/uuid" + "github.com/netbirdio/netbird/client/internal/netflow/types" + "github.com/stretchr/testify/assert" +) + +var random = rand.New(rand.NewSource(time.Now().UnixNano())) + +func TestFlowAggregation(t *testing.T) { + var protocols = []types.Protocol{types.ICMP, types.ICMPv6, types.TCP, types.UDP} + var tests = []struct { + description string + eventTypes []types.Type + }{ + { + description: "start and stop", + eventTypes: []types.Type{types.TypeStart, types.TypeEnd}, + }, + { + description: "start and drop", + eventTypes: []types.Type{types.TypeStart, types.TypeDrop}, + }, + { + description: "start only", + eventTypes: []types.Type{types.TypeStart}, + }, + { + description: "drop only", + eventTypes: []types.Type{types.TypeDrop}, + }} + + for _, protocol := range protocols { + for _, tt := range tests { + t.Run(tt.description+" "+protocol.String(), func(t *testing.T) { + store := NewAggregatingMemoryStore() + allExpected := make([]*types.Event, 0) + + for i := 0; i < 2; i++ { + inEvents, expected := generateEvents(tt.eventTypes, protocol, types.Ingress, 0) + for _, e := range inEvents { + store.StoreEvent(e) + } + allExpected = append(allExpected, expected) + } + + events := store.GetAggregatedEvents() + assert.ElementsMatch(t, events, allExpected) + }) + } + } +} + +func TestIcmpEventAggregation(t *testing.T) { + var protocols = []types.Protocol{types.ICMP, types.ICMPv6} + var icmpTypes = []uint8{1, 2, 3} + + var tests = []struct { + description string + eventTypes []types.Type + }{ + { + description: "start and stop", + eventTypes: []types.Type{types.TypeStart, types.TypeEnd}, + }, + { + description: "start and drop", + eventTypes: []types.Type{types.TypeStart, types.TypeDrop}, + }, + { + description: "start only", + eventTypes: []types.Type{types.TypeStart}, + }, + { + description: "drop only", + eventTypes: []types.Type{types.TypeDrop}, + }} + + for _, protocol := range protocols { + for _, tt := range tests { + t.Run(tt.description+" "+protocol.String(), func(t *testing.T) { + store := NewAggregatingMemoryStore() + allExpected := make([]*types.Event, 0) + for _, icmpType := range icmpTypes { + events, expected := generateEvents(tt.eventTypes, protocol, types.Ingress, icmpType) + for _, e := range events { + store.StoreEvent(e) + } + allExpected = append(allExpected, expected) + } + aggregatedEvents := store.GetAggregatedEvents() + assert.Len(t, aggregatedEvents, len(allExpected)) + assert.ElementsMatch(t, aggregatedEvents, allExpected) + }) + } + } +} + +func ipAddr(a string) netip.Addr { + addr, _ := netip.ParseAddr(a) + return addr +} + +func generateEvents(eventTypes []types.Type, protocol types.Protocol, direction types.Direction, icmpType uint8) ([]*types.Event, *types.Event) { + var rxPackets, txPackets, rxBytes, txBytes uint64 + inEvents := make([]*types.Event, 0) + ts := time.Now() + flowId := uuid.New() + srcIp := ipAddr("1.1.1.1") + srcPort := uint16(random.Uint32() >> 16) + dstIp := ipAddr("2.2.2.2") + dstPort := uint16(random.Uint32() >> 16) + + for idx, eventType := range eventTypes { + e := &types.Event{ + ID: uuid.New(), + Timestamp: ts.Add(time.Duration(idx) * time.Second), + EventFields: types.EventFields{ + FlowID: flowId, + Type: eventType, + Protocol: protocol, + RuleID: []byte("rule-id-1"), + Direction: direction, + SourceIP: srcIp, + SourcePort: srcPort, + DestIP: dstIp, + DestPort: dstPort, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: random.Uint64(), + TxPackets: random.Uint64(), + RxBytes: random.Uint64(), + TxBytes: random.Uint64(), + }} + rxBytes += e.RxBytes + txBytes += e.TxBytes + rxPackets += e.RxPackets + txPackets += e.TxPackets + inEvents = append(inEvents, e) + if protocol == types.ICMP || protocol == types.ICMPv6 { + e.ICMPType = icmpType + } + } + + var start, end, drop uint64 + for _, eventType := range eventTypes { + switch eventType { + case types.TypeStart: + start += 1 + case types.TypeDrop: + drop += 1 + case types.TypeEnd: + end += 1 + } + } + aggregatedEvent := &types.Event{ + ID: inEvents[0].ID, + Timestamp: inEvents[0].Timestamp, + EventFields: types.EventFields{ + FlowID: flowId, + Type: inEvents[0].Type, + Protocol: inEvents[0].Protocol, + RuleID: []byte("rule-id-1"), + Direction: inEvents[0].Direction, + SourceIP: srcIp, + SourcePort: srcPort, + DestIP: dstIp, + DestPort: dstPort, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: rxPackets, + TxPackets: txPackets, + RxBytes: rxBytes, + TxBytes: txBytes, + NumOfStarts: start, + NumOfEnds: end, + NumOfDrops: drop, + }} + if protocol == types.ICMP || protocol == types.ICMPv6 { + aggregatedEvent.ICMPType = icmpType + } + + return inEvents, aggregatedEvent +} diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index 321a9b81fde..1a3b9227a7a 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -81,7 +81,7 @@ type aggregationKey struct { func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { aggregated := make(map[aggregationKey]*types.Event) for _, v := range am.events { - lookupKey := aggregationKey{destAddr: v.DestIP, destPort: v.DestPort, protocol: uint8(v.Protocol), icmpType: v.ICMPCode} + lookupKey := aggregationKey{destAddr: v.DestIP, destPort: v.DestPort, protocol: uint8(v.Protocol), icmpType: v.ICMPType} if _, ok := aggregated[lookupKey]; !ok { aggregated[lookupKey] = v.Clone() event := aggregated[lookupKey] diff --git a/client/internal/netflow/store/tcp_aggregation_test.go b/client/internal/netflow/store/tcp_aggregation_test.go deleted file mode 100644 index a4c9eab95ee..00000000000 --- a/client/internal/netflow/store/tcp_aggregation_test.go +++ /dev/null @@ -1,281 +0,0 @@ -package store - -import ( - "net/netip" - "testing" - "time" - - "github.com/google/uuid" - "github.com/netbirdio/netbird/client/internal/netflow/types" - "github.com/stretchr/testify/assert" -) - -var pregeneratedUUIDs = func() []uuid.UUID { - toret := make([]uuid.UUID, 0) - for range make([]int, 10) { - toret = append(toret, uuid.New()) - } - return toret -}() - -func TestFlowAggregation(t *testing.T) { - var protocols = []types.Protocol{types.ICMP, types.ICMPv6, types.TCP, types.UDP} - var tests = []struct { - description string - events []*types.Event - expected []*types.Event - }{ - { - description: "start and stop", - events: []*types.Event{ - { - ID: pregeneratedUUIDs[0], - Timestamp: time.Unix(100, 100), - EventFields: types.EventFields{ - FlowID: pregeneratedUUIDs[1], - Type: types.TypeStart, - RuleID: []byte("rule-id-1"), - Direction: types.Egress, - SourceIP: ipAddr("1.1.1.1"), - SourcePort: 1234, - DestIP: ipAddr("2.2.2.2"), - DestPort: 443, - SourceResourceID: []byte("source-resource-id"), - DestResourceID: []byte("dest-resource-id"), - RxPackets: 10, - TxPackets: 20, - RxBytes: 10000, - TxBytes: 20000, - }}, - { - ID: pregeneratedUUIDs[2], - Timestamp: time.Unix(100, 100).Add(time.Second), - EventFields: types.EventFields{ - FlowID: pregeneratedUUIDs[1], - Type: types.TypeEnd, - RuleID: []byte("rule-id-1"), - Direction: types.Egress, - SourceIP: ipAddr("1.1.1.1"), - SourcePort: 1234, - DestIP: ipAddr("2.2.2.2"), - DestPort: 443, - SourceResourceID: []byte("source-resource-id"), - DestResourceID: []byte("dest-resource-id"), - RxPackets: 30, - TxPackets: 40, - RxBytes: 30000, - TxBytes: 40000, - }}, - }, - expected: []*types.Event{ - { - ID: pregeneratedUUIDs[0], - Timestamp: time.Unix(100, 100), - EventFields: types.EventFields{ - FlowID: pregeneratedUUIDs[1], - Type: types.TypeStart, - RuleID: []byte("rule-id-1"), - Direction: types.Egress, - SourceIP: ipAddr("1.1.1.1"), - SourcePort: 1234, - DestIP: ipAddr("2.2.2.2"), - DestPort: 443, - SourceResourceID: []byte("source-resource-id"), - DestResourceID: []byte("dest-resource-id"), - RxPackets: 40, - TxPackets: 60, - RxBytes: 40000, - TxBytes: 60000, - NumOfStarts: 1, - NumOfEnds: 1, - NumOfDrops: 0, - }}, - }, - }, - { - description: "start and drop", - events: []*types.Event{ - { - ID: pregeneratedUUIDs[0], - Timestamp: time.Unix(100, 100), - EventFields: types.EventFields{ - FlowID: pregeneratedUUIDs[1], - Type: types.TypeStart, - RuleID: []byte("rule-id-1"), - Direction: types.Egress, - SourceIP: ipAddr("1.1.1.1"), - SourcePort: 1234, - DestIP: ipAddr("2.2.2.2"), - DestPort: 443, - SourceResourceID: []byte("source-resource-id"), - DestResourceID: []byte("dest-resource-id"), - RxPackets: 10, - TxPackets: 20, - RxBytes: 10000, - TxBytes: 20000, - }}, - { - ID: pregeneratedUUIDs[2], - Timestamp: time.Unix(100, 100).Add(time.Second), - EventFields: types.EventFields{ - FlowID: pregeneratedUUIDs[1], - Type: types.TypeDrop, - RuleID: []byte("rule-id-1"), - Direction: types.Egress, - SourceIP: ipAddr("1.1.1.1"), - SourcePort: 1234, - DestIP: ipAddr("2.2.2.2"), - DestPort: 443, - SourceResourceID: []byte("source-resource-id"), - DestResourceID: []byte("dest-resource-id"), - RxPackets: 30, - TxPackets: 40, - RxBytes: 30000, - TxBytes: 40000, - }}, - }, - expected: []*types.Event{ - { - ID: pregeneratedUUIDs[0], - Timestamp: time.Unix(100, 100), - EventFields: types.EventFields{ - FlowID: pregeneratedUUIDs[1], - Type: types.TypeStart, - RuleID: []byte("rule-id-1"), - Direction: types.Egress, - SourceIP: ipAddr("1.1.1.1"), - SourcePort: 1234, - DestIP: ipAddr("2.2.2.2"), - DestPort: 443, - SourceResourceID: []byte("source-resource-id"), - DestResourceID: []byte("dest-resource-id"), - RxPackets: 40, - TxPackets: 60, - RxBytes: 40000, - TxBytes: 60000, - NumOfStarts: 1, - NumOfEnds: 0, - NumOfDrops: 1, - }}, - }, - }, - { - description: "start only", - events: []*types.Event{ - { - ID: pregeneratedUUIDs[0], - Timestamp: time.Unix(100, 100), - EventFields: types.EventFields{ - FlowID: pregeneratedUUIDs[1], - Type: types.TypeStart, - RuleID: []byte("rule-id-1"), - Direction: types.Egress, - SourceIP: ipAddr("1.1.1.1"), - SourcePort: 1234, - DestIP: ipAddr("2.2.2.2"), - DestPort: 443, - SourceResourceID: []byte("source-resource-id"), - DestResourceID: []byte("dest-resource-id"), - RxPackets: 10, - TxPackets: 20, - RxBytes: 10000, - TxBytes: 20000, - }}, - }, - expected: []*types.Event{ - { - ID: pregeneratedUUIDs[0], - Timestamp: time.Unix(100, 100), - EventFields: types.EventFields{ - FlowID: pregeneratedUUIDs[1], - Type: types.TypeStart, - RuleID: []byte("rule-id-1"), - Direction: types.Egress, - SourceIP: ipAddr("1.1.1.1"), - SourcePort: 1234, - DestIP: ipAddr("2.2.2.2"), - DestPort: 443, - SourceResourceID: []byte("source-resource-id"), - DestResourceID: []byte("dest-resource-id"), - RxPackets: 10, - TxPackets: 20, - RxBytes: 10000, - TxBytes: 20000, - NumOfStarts: 1, - NumOfEnds: 0, - NumOfDrops: 0, - }}, - }, - }, - { - description: "drop only", - events: []*types.Event{ - { - ID: pregeneratedUUIDs[2], - Timestamp: time.Unix(100, 100).Add(time.Second), - EventFields: types.EventFields{ - FlowID: pregeneratedUUIDs[1], - Type: types.TypeDrop, - RuleID: []byte("rule-id-1"), - Direction: types.Egress, - SourceIP: ipAddr("1.1.1.1"), - SourcePort: 1234, - DestIP: ipAddr("2.2.2.2"), - DestPort: 443, - SourceResourceID: []byte("source-resource-id"), - DestResourceID: []byte("dest-resource-id"), - RxPackets: 30, - TxPackets: 40, - RxBytes: 30000, - TxBytes: 40000, - }}, - }, - expected: []*types.Event{ - { - ID: pregeneratedUUIDs[2], - Timestamp: time.Unix(100, 100).Add(time.Second), - EventFields: types.EventFields{ - FlowID: pregeneratedUUIDs[1], - Type: types.TypeDrop, - RuleID: []byte("rule-id-1"), - Direction: types.Egress, - SourceIP: ipAddr("1.1.1.1"), - SourcePort: 1234, - DestIP: ipAddr("2.2.2.2"), - DestPort: 443, - SourceResourceID: []byte("source-resource-id"), - DestResourceID: []byte("dest-resource-id"), - RxPackets: 30, - TxPackets: 40, - RxBytes: 30000, - TxBytes: 40000, - NumOfStarts: 0, - NumOfEnds: 0, - NumOfDrops: 1, - }}, - }, - }} - - for _, protocol := range protocols { - for _, tt := range tests { - t.Run(tt.description+" "+protocol.String(), func(t *testing.T) { - store := NewAggregatingMemoryStore() - for _, e := range tt.events { - e.Protocol = protocol - store.StoreEvent(e) - } - for _, e := range tt.expected { - e.Protocol = protocol - } - events := store.GetAggregatedEvents() - assert.Len(t, events, len(tt.expected)) - assert.ElementsMatch(t, events, tt.expected) - }) - } - } -} - -func ipAddr(a string) netip.Addr { - addr, _ := netip.ParseAddr(a) - return addr -} From e3f93965783e7c1bd01c4f7707fa197700e31410 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Mon, 15 Jun 2026 10:36:59 +0200 Subject: [PATCH 12/30] regenerate protobufs with expected versions of protoc and protoc-gen-go Signed-off-by: Dmitri --- flow/proto/flow.pb.go | 346 ++++++++++++++++++++++++------------- flow/proto/flow_grpc.pb.go | 2 +- 2 files changed, 223 insertions(+), 125 deletions(-) diff --git a/flow/proto/flow.pb.go b/flow/proto/flow.pb.go index 955a6e02648..b9f0d7b94c2 100644 --- a/flow/proto/flow.pb.go +++ b/flow/proto/flow.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 -// protoc v7.34.1 +// protoc-gen-go v1.26.0 +// protoc v3.21.9 // source: flow.proto package proto @@ -12,7 +12,6 @@ import ( timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" - unsafe "unsafe" ) const ( @@ -126,24 +125,27 @@ func (Direction) EnumDescriptor() ([]byte, []int) { } type FlowEvent struct { - state protoimpl.MessageState `protogen:"open.v1"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + // Unique client event identifier EventId []byte `protobuf:"bytes,1,opt,name=event_id,json=eventId,proto3" json:"event_id,omitempty"` // When the event occurred Timestamp *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Public key of the sending peer - PublicKey []byte `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` - FlowFields *FlowFields `protobuf:"bytes,4,opt,name=flow_fields,json=flowFields,proto3" json:"flow_fields,omitempty"` - IsInitiator bool `protobuf:"varint,5,opt,name=isInitiator,proto3" json:"isInitiator,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + PublicKey []byte `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + FlowFields *FlowFields `protobuf:"bytes,4,opt,name=flow_fields,json=flowFields,proto3" json:"flow_fields,omitempty"` + IsInitiator bool `protobuf:"varint,5,opt,name=isInitiator,proto3" json:"isInitiator,omitempty"` } func (x *FlowEvent) Reset() { *x = FlowEvent{} - mi := &file_flow_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) + if protoimpl.UnsafeEnabled { + mi := &file_flow_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } func (x *FlowEvent) String() string { @@ -154,7 +156,7 @@ func (*FlowEvent) ProtoMessage() {} func (x *FlowEvent) ProtoReflect() protoreflect.Message { mi := &file_flow_proto_msgTypes[0] - if x != nil { + if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -205,19 +207,22 @@ func (x *FlowEvent) GetIsInitiator() bool { } type FlowEventAck struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Unique client event identifier that has been ack'ed - EventId []byte `protobuf:"bytes,1,opt,name=event_id,json=eventId,proto3" json:"event_id,omitempty"` - IsInitiator bool `protobuf:"varint,2,opt,name=isInitiator,proto3" json:"isInitiator,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Unique client event identifier that has been ack'ed + EventId []byte `protobuf:"bytes,1,opt,name=event_id,json=eventId,proto3" json:"event_id,omitempty"` + IsInitiator bool `protobuf:"varint,2,opt,name=isInitiator,proto3" json:"isInitiator,omitempty"` } func (x *FlowEventAck) Reset() { *x = FlowEventAck{} - mi := &file_flow_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) + if protoimpl.UnsafeEnabled { + mi := &file_flow_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } func (x *FlowEventAck) String() string { @@ -228,7 +233,7 @@ func (*FlowEventAck) ProtoMessage() {} func (x *FlowEventAck) ProtoReflect() protoreflect.Message { mi := &file_flow_proto_msgTypes[1] - if x != nil { + if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -258,7 +263,10 @@ func (x *FlowEventAck) GetIsInitiator() bool { } type FlowFields struct { - state protoimpl.MessageState `protogen:"open.v1"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + // Unique client flow session identifier FlowId []byte `protobuf:"bytes,1,opt,name=flow_id,json=flowId,proto3" json:"flow_id,omitempty"` // Flow type @@ -275,8 +283,7 @@ type FlowFields struct { DestIp []byte `protobuf:"bytes,7,opt,name=dest_ip,json=destIp,proto3" json:"dest_ip,omitempty"` // Layer 4 -specific information // - // Types that are valid to be assigned to ConnectionInfo: - // + // Types that are assignable to ConnectionInfo: // *FlowFields_PortInfo // *FlowFields_IcmpInfo ConnectionInfo isFlowFields_ConnectionInfo `protobuf_oneof:"connection_info"` @@ -292,15 +299,15 @@ type FlowFields struct { NumOfStarts uint64 `protobuf:"varint,16,opt,name=num_of_starts,json=numOfStarts,proto3" json:"num_of_starts,omitempty"` NumOfEnds uint64 `protobuf:"varint,17,opt,name=num_of_ends,json=numOfEnds,proto3" json:"num_of_ends,omitempty"` NumOfDrops uint64 `protobuf:"varint,18,opt,name=num_of_drops,json=numOfDrops,proto3" json:"num_of_drops,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache } func (x *FlowFields) Reset() { *x = FlowFields{} - mi := &file_flow_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) + if protoimpl.UnsafeEnabled { + mi := &file_flow_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } func (x *FlowFields) String() string { @@ -311,7 +318,7 @@ func (*FlowFields) ProtoMessage() {} func (x *FlowFields) ProtoReflect() protoreflect.Message { mi := &file_flow_proto_msgTypes[2] - if x != nil { + if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -375,27 +382,23 @@ func (x *FlowFields) GetDestIp() []byte { return nil } -func (x *FlowFields) GetConnectionInfo() isFlowFields_ConnectionInfo { - if x != nil { - return x.ConnectionInfo +func (m *FlowFields) GetConnectionInfo() isFlowFields_ConnectionInfo { + if m != nil { + return m.ConnectionInfo } return nil } func (x *FlowFields) GetPortInfo() *PortInfo { - if x != nil { - if x, ok := x.ConnectionInfo.(*FlowFields_PortInfo); ok { - return x.PortInfo - } + if x, ok := x.GetConnectionInfo().(*FlowFields_PortInfo); ok { + return x.PortInfo } return nil } func (x *FlowFields) GetIcmpInfo() *ICMPInfo { - if x != nil { - if x, ok := x.ConnectionInfo.(*FlowFields_IcmpInfo); ok { - return x.IcmpInfo - } + if x, ok := x.GetConnectionInfo().(*FlowFields_IcmpInfo); ok { + return x.IcmpInfo } return nil } @@ -483,18 +486,21 @@ func (*FlowFields_IcmpInfo) isFlowFields_ConnectionInfo() {} // TCP/UDP port information type PortInfo struct { - state protoimpl.MessageState `protogen:"open.v1"` - SourcePort uint32 `protobuf:"varint,1,opt,name=source_port,json=sourcePort,proto3" json:"source_port,omitempty"` - DestPort uint32 `protobuf:"varint,2,opt,name=dest_port,json=destPort,proto3" json:"dest_port,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SourcePort uint32 `protobuf:"varint,1,opt,name=source_port,json=sourcePort,proto3" json:"source_port,omitempty"` + DestPort uint32 `protobuf:"varint,2,opt,name=dest_port,json=destPort,proto3" json:"dest_port,omitempty"` } func (x *PortInfo) Reset() { *x = PortInfo{} - mi := &file_flow_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) + if protoimpl.UnsafeEnabled { + mi := &file_flow_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } func (x *PortInfo) String() string { @@ -505,7 +511,7 @@ func (*PortInfo) ProtoMessage() {} func (x *PortInfo) ProtoReflect() protoreflect.Message { mi := &file_flow_proto_msgTypes[3] - if x != nil { + if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -536,18 +542,21 @@ func (x *PortInfo) GetDestPort() uint32 { // ICMP message information type ICMPInfo struct { - state protoimpl.MessageState `protogen:"open.v1"` - IcmpType uint32 `protobuf:"varint,1,opt,name=icmp_type,json=icmpType,proto3" json:"icmp_type,omitempty"` - IcmpCode uint32 `protobuf:"varint,2,opt,name=icmp_code,json=icmpCode,proto3" json:"icmp_code,omitempty"` - unknownFields protoimpl.UnknownFields + state protoimpl.MessageState sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IcmpType uint32 `protobuf:"varint,1,opt,name=icmp_type,json=icmpType,proto3" json:"icmp_type,omitempty"` + IcmpCode uint32 `protobuf:"varint,2,opt,name=icmp_code,json=icmpCode,proto3" json:"icmp_code,omitempty"` } func (x *ICMPInfo) Reset() { *x = ICMPInfo{} - mi := &file_flow_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) + if protoimpl.UnsafeEnabled { + mi := &file_flow_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } func (x *ICMPInfo) String() string { @@ -558,7 +567,7 @@ func (*ICMPInfo) ProtoMessage() {} func (x *ICMPInfo) ProtoReflect() protoreflect.Message { mi := &file_flow_proto_msgTypes[4] - if x != nil { + if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -589,83 +598,109 @@ func (x *ICMPInfo) GetIcmpCode() uint32 { var File_flow_proto protoreflect.FileDescriptor -const file_flow_proto_rawDesc = "" + - "\n" + - "\n" + - "flow.proto\x12\x04flow\x1a\x1fgoogle/protobuf/timestamp.proto\"\xd4\x01\n" + - "\tFlowEvent\x12\x19\n" + - "\bevent_id\x18\x01 \x01(\fR\aeventId\x128\n" + - "\ttimestamp\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\x12\x1d\n" + - "\n" + - "public_key\x18\x03 \x01(\fR\tpublicKey\x121\n" + - "\vflow_fields\x18\x04 \x01(\v2\x10.flow.FlowFieldsR\n" + - "flowFields\x12 \n" + - "\visInitiator\x18\x05 \x01(\bR\visInitiator\"K\n" + - "\fFlowEventAck\x12\x19\n" + - "\bevent_id\x18\x01 \x01(\fR\aeventId\x12 \n" + - "\visInitiator\x18\x02 \x01(\bR\visInitiator\"\x82\x05\n" + - "\n" + - "FlowFields\x12\x17\n" + - "\aflow_id\x18\x01 \x01(\fR\x06flowId\x12\x1e\n" + - "\x04type\x18\x02 \x01(\x0e2\n" + - ".flow.TypeR\x04type\x12\x17\n" + - "\arule_id\x18\x03 \x01(\fR\x06ruleId\x12-\n" + - "\tdirection\x18\x04 \x01(\x0e2\x0f.flow.DirectionR\tdirection\x12\x1a\n" + - "\bprotocol\x18\x05 \x01(\rR\bprotocol\x12\x1b\n" + - "\tsource_ip\x18\x06 \x01(\fR\bsourceIp\x12\x17\n" + - "\adest_ip\x18\a \x01(\fR\x06destIp\x12-\n" + - "\tport_info\x18\b \x01(\v2\x0e.flow.PortInfoH\x00R\bportInfo\x12-\n" + - "\ticmp_info\x18\t \x01(\v2\x0e.flow.ICMPInfoH\x00R\bicmpInfo\x12\x1d\n" + - "\n" + - "rx_packets\x18\n" + - " \x01(\x04R\trxPackets\x12\x1d\n" + - "\n" + - "tx_packets\x18\v \x01(\x04R\ttxPackets\x12\x19\n" + - "\brx_bytes\x18\f \x01(\x04R\arxBytes\x12\x19\n" + - "\btx_bytes\x18\r \x01(\x04R\atxBytes\x12,\n" + - "\x12source_resource_id\x18\x0e \x01(\fR\x10sourceResourceId\x12(\n" + - "\x10dest_resource_id\x18\x0f \x01(\fR\x0edestResourceId\x12\"\n" + - "\rnum_of_starts\x18\x10 \x01(\x04R\vnumOfStarts\x12\x1e\n" + - "\vnum_of_ends\x18\x11 \x01(\x04R\tnumOfEnds\x12 \n" + - "\fnum_of_drops\x18\x12 \x01(\x04R\n" + - "numOfDropsB\x11\n" + - "\x0fconnection_info\"H\n" + - "\bPortInfo\x12\x1f\n" + - "\vsource_port\x18\x01 \x01(\rR\n" + - "sourcePort\x12\x1b\n" + - "\tdest_port\x18\x02 \x01(\rR\bdestPort\"D\n" + - "\bICMPInfo\x12\x1b\n" + - "\ticmp_type\x18\x01 \x01(\rR\bicmpType\x12\x1b\n" + - "\ticmp_code\x18\x02 \x01(\rR\bicmpCode*E\n" + - "\x04Type\x12\x10\n" + - "\fTYPE_UNKNOWN\x10\x00\x12\x0e\n" + - "\n" + - "TYPE_START\x10\x01\x12\f\n" + - "\bTYPE_END\x10\x02\x12\r\n" + - "\tTYPE_DROP\x10\x03*;\n" + - "\tDirection\x12\x15\n" + - "\x11DIRECTION_UNKNOWN\x10\x00\x12\v\n" + - "\aINGRESS\x10\x01\x12\n" + - "\n" + - "\x06EGRESS\x10\x022B\n" + - "\vFlowService\x123\n" + - "\x06Events\x12\x0f.flow.FlowEvent\x1a\x12.flow.FlowEventAck\"\x00(\x010\x01B\bZ\x06/protob\x06proto3" +var file_flow_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x66, 0x6c, + 0x6f, 0x77, 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, 0x22, 0xd4, 0x01, 0x0a, 0x09, 0x46, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 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, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x66, 0x6c, 0x6f, + 0x77, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x0a, 0x66, 0x6c, + 0x6f, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x49, 0x6e, + 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, + 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x4b, 0x0a, 0x0c, 0x46, 0x6c, + 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, + 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x49, 0x6e, + 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x82, 0x05, 0x0a, 0x0a, 0x46, 0x6c, 0x6f, 0x77, + 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x12, + 0x1e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, + 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, + 0x17, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x06, 0x72, 0x75, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x66, 0x6c, + 0x6f, 0x77, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, + 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x6f, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x70, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x70, + 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x64, 0x65, 0x73, 0x74, 0x49, 0x70, 0x12, 0x2d, 0x0a, 0x09, 0x70, 0x6f, 0x72, + 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x66, + 0x6c, 0x6f, 0x77, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x08, + 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2d, 0x0a, 0x09, 0x69, 0x63, 0x6d, 0x70, + 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x66, 0x6c, + 0x6f, 0x77, 0x2e, 0x49, 0x43, 0x4d, 0x50, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x08, 0x69, + 0x63, 0x6d, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x78, 0x5f, 0x70, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x78, 0x50, + 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x78, 0x5f, 0x70, 0x61, 0x63, + 0x6b, 0x65, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x78, 0x50, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x78, 0x5f, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x72, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, + 0x12, 0x19, 0x0a, 0x08, 0x74, 0x78, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x07, 0x74, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x73, + 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0f, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x4f, + 0x66, 0x53, 0x74, 0x61, 0x72, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, + 0x66, 0x5f, 0x65, 0x6e, 0x64, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6e, 0x75, + 0x6d, 0x4f, 0x66, 0x45, 0x6e, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, + 0x66, 0x5f, 0x64, 0x72, 0x6f, 0x70, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6e, + 0x75, 0x6d, 0x4f, 0x66, 0x44, 0x72, 0x6f, 0x70, 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x48, 0x0a, 0x08, + 0x50, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x73, + 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, + 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x22, 0x44, 0x0a, 0x08, 0x49, 0x43, 0x4d, 0x50, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x63, 0x6d, 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x69, 0x63, 0x6d, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x69, 0x63, 0x6d, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x08, 0x69, 0x63, 0x6d, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x2a, 0x45, 0x0a, 0x04, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, + 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, + 0x54, 0x41, 0x52, 0x54, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, + 0x4e, 0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x52, 0x4f, + 0x50, 0x10, 0x03, 0x2a, 0x3b, 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x15, 0x0a, 0x11, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x47, 0x52, 0x45, + 0x53, 0x53, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x02, + 0x32, 0x42, 0x0a, 0x0b, 0x46, 0x6c, 0x6f, 0x77, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x33, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x0f, 0x2e, 0x66, 0x6c, 0x6f, 0x77, + 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x12, 0x2e, 0x66, 0x6c, 0x6f, + 0x77, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x22, 0x00, + 0x28, 0x01, 0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} var ( file_flow_proto_rawDescOnce sync.Once - file_flow_proto_rawDescData []byte + file_flow_proto_rawDescData = file_flow_proto_rawDesc ) func file_flow_proto_rawDescGZIP() []byte { file_flow_proto_rawDescOnce.Do(func() { - file_flow_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_flow_proto_rawDesc), len(file_flow_proto_rawDesc))) + file_flow_proto_rawDescData = protoimpl.X.CompressGZIP(file_flow_proto_rawDescData) }) return file_flow_proto_rawDescData } var file_flow_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_flow_proto_msgTypes = make([]protoimpl.MessageInfo, 5) -var file_flow_proto_goTypes = []any{ +var file_flow_proto_goTypes = []interface{}{ (Type)(0), // 0: flow.Type (Direction)(0), // 1: flow.Direction (*FlowEvent)(nil), // 2: flow.FlowEvent @@ -696,7 +731,69 @@ func file_flow_proto_init() { if File_flow_proto != nil { return } - file_flow_proto_msgTypes[2].OneofWrappers = []any{ + if !protoimpl.UnsafeEnabled { + file_flow_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlowEvent); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_flow_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlowEventAck); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_flow_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlowFields); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_flow_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PortInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_flow_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ICMPInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_flow_proto_msgTypes[2].OneofWrappers = []interface{}{ (*FlowFields_PortInfo)(nil), (*FlowFields_IcmpInfo)(nil), } @@ -704,7 +801,7 @@ func file_flow_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: unsafe.Slice(unsafe.StringData(file_flow_proto_rawDesc), len(file_flow_proto_rawDesc)), + RawDescriptor: file_flow_proto_rawDesc, NumEnums: 2, NumMessages: 5, NumExtensions: 0, @@ -716,6 +813,7 @@ func file_flow_proto_init() { MessageInfos: file_flow_proto_msgTypes, }.Build() File_flow_proto = out.File + file_flow_proto_rawDesc = nil file_flow_proto_goTypes = nil file_flow_proto_depIdxs = nil } diff --git a/flow/proto/flow_grpc.pb.go b/flow/proto/flow_grpc.pb.go index 7f34aa317d6..9ae9702a5aa 100644 --- a/flow/proto/flow_grpc.pb.go +++ b/flow/proto/flow_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.6.1 -// - protoc v7.34.1 +// - protoc v3.21.9 // source: flow.proto package proto From c875aa6b4b3e1ef9fc2de54985b956e4c3015a6d Mon Sep 17 00:00:00 2001 From: Dmitri Date: Mon, 15 Jun 2026 10:45:34 +0200 Subject: [PATCH 13/30] remove protoc/protoc-gen headers from flow_grpc.pb.go Signed-off-by: Dmitri --- flow/proto/flow_grpc.pb.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/flow/proto/flow_grpc.pb.go b/flow/proto/flow_grpc.pb.go index 9ae9702a5aa..6d9a392d053 100644 --- a/flow/proto/flow_grpc.pb.go +++ b/flow/proto/flow_grpc.pb.go @@ -1,13 +1,8 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.6.1 -// - protoc v3.21.9 -// source: flow.proto - package proto import ( context "context" + grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" From 9dc5e77ec0ecac1bdeed6a013a79086ab1f816f5 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Mon, 15 Jun 2026 13:05:16 +0200 Subject: [PATCH 14/30] updated openapi spec Signed-off-by: Dmitri --- shared/management/http/api/types.gen.go | 141 +----------------------- 1 file changed, 3 insertions(+), 138 deletions(-) diff --git a/shared/management/http/api/types.gen.go b/shared/management/http/api/types.gen.go index d7945e448f4..1336e16ffec 100644 --- a/shared/management/http/api/types.gen.go +++ b/shared/management/http/api/types.gen.go @@ -1,6 +1,6 @@ // Package api provides primitives to interact with the openapi HTTP API. // -// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.7.0 DO NOT EDIT. +// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.7.1 DO NOT EDIT. package api import ( @@ -959,30 +959,6 @@ func (e SentinelOneMatchAttributesNetworkStatus) Valid() bool { } } -// Defines values for ServiceMode. -const ( - ServiceModeHttp ServiceMode = "http" - ServiceModeTcp ServiceMode = "tcp" - ServiceModeTls ServiceMode = "tls" - ServiceModeUdp ServiceMode = "udp" -) - -// Valid indicates whether the value is a known member of the ServiceMode enum. -func (e ServiceMode) Valid() bool { - switch e { - case ServiceModeHttp: - return true - case ServiceModeTcp: - return true - case ServiceModeTls: - return true - case ServiceModeUdp: - return true - default: - return false - } -} - // Defines values for ServiceMetaStatus. const ( ServiceMetaStatusActive ServiceMetaStatus = "active" @@ -1013,30 +989,6 @@ func (e ServiceMetaStatus) Valid() bool { } } -// Defines values for ServiceRequestMode. -const ( - ServiceRequestModeHttp ServiceRequestMode = "http" - ServiceRequestModeTcp ServiceRequestMode = "tcp" - ServiceRequestModeTls ServiceRequestMode = "tls" - ServiceRequestModeUdp ServiceRequestMode = "udp" -) - -// Valid indicates whether the value is a known member of the ServiceRequestMode enum. -func (e ServiceRequestMode) Valid() bool { - switch e { - case ServiceRequestModeHttp: - return true - case ServiceRequestModeTcp: - return true - case ServiceRequestModeTls: - return true - case ServiceRequestModeUdp: - return true - default: - return false - } -} - // Defines values for ServiceTargetProtocol. const ( ServiceTargetProtocolHttp ServiceTargetProtocol = "http" @@ -4093,57 +4045,7 @@ type SentinelOneMatchAttributes struct { type SentinelOneMatchAttributesNetworkStatus string // Service defines model for Service. -type Service struct { - // AccessGroups NetBird group IDs whose peers may reach this private service over the tunnel. Required when private=true; ignored otherwise. Mutually exclusive with bearer auth (SSO). - AccessGroups *[]string `json:"access_groups,omitempty"` - - // AccessRestrictions Connection-level access restrictions based on IP address or geography. Applies to both HTTP and L4 services. - AccessRestrictions *AccessRestrictions `json:"access_restrictions,omitempty"` - Auth ServiceAuthConfig `json:"auth"` - - // Domain Domain for the service - Domain string `json:"domain"` - - // Enabled Whether the service is enabled - Enabled bool `json:"enabled"` - - // Id Service ID - Id string `json:"id"` - - // ListenPort Port the proxy listens on (L4/TLS only) - ListenPort *int `json:"listen_port,omitempty"` - Meta ServiceMeta `json:"meta"` - - // Mode Service mode. "http" for L7 reverse proxy, "tcp"/"udp"/"tls" for L4 passthrough. - Mode *ServiceMode `json:"mode,omitempty"` - - // Name Service name - Name string `json:"name"` - - // PassHostHeader When true, the original client Host header is passed through to the backend instead of being rewritten to the backend's address - PassHostHeader *bool `json:"pass_host_header,omitempty"` - - // PortAutoAssigned Whether the listen port was auto-assigned - PortAutoAssigned *bool `json:"port_auto_assigned,omitempty"` - - // Private When true, the service is NetBird-only — its target points at a proxy cluster, inbound peers authenticate via their WireGuard tunnel identity (no OIDC), and an ACL policy is auto-generated from access_groups to the cluster's proxy-peer group. Requires mode=http. - Private *bool `json:"private,omitempty"` - - // ProxyCluster The proxy cluster handling this service (derived from domain) - ProxyCluster *string `json:"proxy_cluster,omitempty"` - - // RewriteRedirects When true, Location headers in backend responses are rewritten to replace the backend address with the public-facing domain - RewriteRedirects *bool `json:"rewrite_redirects,omitempty"` - - // Targets List of target backends for this service - Targets []ServiceTarget `json:"targets"` - - // Terminated Whether the service has been terminated. Terminated services cannot be updated. Services that violate the Terms of Service will be terminated. - Terminated *bool `json:"terminated,omitempty"` -} - -// ServiceMode Service mode. "http" for L7 reverse proxy, "tcp"/"udp"/"tls" for L4 passthrough. -type ServiceMode string +type Service = interface{} // ServiceAuthConfig defines model for ServiceAuthConfig. type ServiceAuthConfig struct { @@ -4170,44 +4072,7 @@ type ServiceMeta struct { type ServiceMetaStatus string // ServiceRequest defines model for ServiceRequest. -type ServiceRequest struct { - // AccessGroups NetBird group IDs whose peers may reach this private service over the tunnel. Required when private=true; ignored otherwise. Mutually exclusive with bearer auth (SSO). - AccessGroups *[]string `json:"access_groups,omitempty"` - - // AccessRestrictions Connection-level access restrictions based on IP address or geography. Applies to both HTTP and L4 services. - AccessRestrictions *AccessRestrictions `json:"access_restrictions,omitempty"` - Auth *ServiceAuthConfig `json:"auth,omitempty"` - - // Domain Domain for the service - Domain string `json:"domain"` - - // Enabled Whether the service is enabled - Enabled bool `json:"enabled"` - - // ListenPort Port the proxy listens on (L4/TLS only). Set to 0 for auto-assignment. - ListenPort *int `json:"listen_port,omitempty"` - - // Mode Service mode. "http" for L7 reverse proxy, "tcp"/"udp"/"tls" for L4 passthrough. - Mode *ServiceRequestMode `json:"mode,omitempty"` - - // Name Service name - Name string `json:"name"` - - // PassHostHeader When true, the original client Host header is passed through to the backend instead of being rewritten to the backend's address - PassHostHeader *bool `json:"pass_host_header,omitempty"` - - // Private When true, the service is NetBird-only — its target points at a proxy cluster, inbound peers authenticate via their WireGuard tunnel identity (no OIDC), and an ACL policy is auto-generated from access_groups to the cluster's proxy-peer group. Requires mode=http. - Private *bool `json:"private,omitempty"` - - // RewriteRedirects When true, Location headers in backend responses are rewritten to replace the backend address with the public-facing domain - RewriteRedirects *bool `json:"rewrite_redirects,omitempty"` - - // Targets List of target backends for this service - Targets *[]ServiceTarget `json:"targets,omitempty"` -} - -// ServiceRequestMode Service mode. "http" for L7 reverse proxy, "tcp"/"udp"/"tls" for L4 passthrough. -type ServiceRequestMode string +type ServiceRequest = interface{} // ServiceTarget defines model for ServiceTarget. type ServiceTarget struct { From 07c527f3fd8897145201be806e64a7201a83fe16 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Mon, 15 Jun 2026 13:23:52 +0200 Subject: [PATCH 15/30] updated openapi NetworkTrafficEvent spec, regenerated types Signed-off-by: Dmitri --- shared/management/http/api/openapi.yml | 12 ++++++++++++ shared/management/http/api/types.gen.go | 15 ++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/shared/management/http/api/openapi.yml b/shared/management/http/api/openapi.yml index f8c687b7b38..465ec3de169 100644 --- a/shared/management/http/api/openapi.yml +++ b/shared/management/http/api/openapi.yml @@ -2765,6 +2765,18 @@ components: type: integer description: "Number of packets transmitted." example: 5 + num_of_starts: + type: integer + description: "Number of start events." + example: 3 + num_of_ends: + type: integer + description: "Number of end events." + example: 4 + num_of_drops: + type: integer + description: "Number of drop events." + example: 5 events: type: array description: "List of events that are correlated to this flow (e.g., start, end)." diff --git a/shared/management/http/api/types.gen.go b/shared/management/http/api/types.gen.go index 1336e16ffec..e1a4399c40d 100644 --- a/shared/management/http/api/types.gen.go +++ b/shared/management/http/api/types.gen.go @@ -2857,9 +2857,18 @@ type NetworkTrafficEvent struct { Events []NetworkTrafficSubEvent `json:"events"` // FlowId FlowID is the ID of the connection flow. Not unique because it can be the same for multiple events (e.g., start and end of the connection). - FlowId string `json:"flow_id"` - Icmp NetworkTrafficICMP `json:"icmp"` - Policy NetworkTrafficPolicy `json:"policy"` + FlowId string `json:"flow_id"` + Icmp NetworkTrafficICMP `json:"icmp"` + + // NumOfDrops Number of drop events. + NumOfDrops *int `json:"num_of_drops,omitempty"` + + // NumOfEnds Number of end events. + NumOfEnds *int `json:"num_of_ends,omitempty"` + + // NumOfStarts Number of start events. + NumOfStarts *int `json:"num_of_starts,omitempty"` + Policy NetworkTrafficPolicy `json:"policy"` // Protocol Protocol is the protocol of the traffic (e.g. 1 = ICMP, 6 = TCP, 17 = UDP, etc.). Protocol int `json:"protocol"` From a93cb66ea1440f267e1e1476d981a8ab6e000472 Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Tue, 16 Jun 2026 14:43:08 +0200 Subject: [PATCH 16/30] respond to feedback Signed-off-by: Dmitri Dolguikh --- client/internal/netflow/manager.go | 10 +++---- .../netflow/store/event_aggregation_test.go | 26 ++++++++++++++----- client/internal/netflow/store/memory.go | 17 +++++++----- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/client/internal/netflow/manager.go b/client/internal/netflow/manager.go index f492098d266..570ecc7a968 100644 --- a/client/internal/netflow/manager.go +++ b/client/internal/netflow/manager.go @@ -249,7 +249,7 @@ func (m *Manager) receiveACKs(ctx context.Context, client *client.GRPCClient) { } func (m *Manager) startRetries(ctx context.Context) { - ticker := time.NewTimer(m.retryInterval) + timer := time.NewTimer(m.retryInterval) retryBackoff := backoff.WithContext(&backoff.ExponentialBackOff{ InitialInterval: 1 * time.Second, RandomizationFactor: 0.5, @@ -259,13 +259,13 @@ func (m *Manager) startRetries(ctx context.Context) { Stop: backoff.Stop, Clock: backoff.SystemClock, }, ctx) - defer ticker.Stop() + defer timer.Stop() for { select { case <-ctx.Done(): return - case <-ticker.C: + case <-timer.C: for _, e := range m.eventsWithoutAcks.GetEvents() { if e.Timestamp.Add(time.Second).After(time.Now()) { // grace period on retries to avoid early retries @@ -273,12 +273,12 @@ func (m *Manager) startRetries(ctx context.Context) { continue } if err := m.send(e); err != nil { - ticker = time.NewTimer(retryBackoff.NextBackOff()) //nolint:staticcheck,wastedassign + timer = time.NewTimer(retryBackoff.NextBackOff()) //nolint:staticcheck,wastedassign break } } retryBackoff.Reset() - ticker = time.NewTimer(time.Second) + timer = time.NewTimer(time.Second) } } } diff --git a/client/internal/netflow/store/event_aggregation_test.go b/client/internal/netflow/store/event_aggregation_test.go index a0fe8ef8e45..8064e0e4a2e 100644 --- a/client/internal/netflow/store/event_aggregation_test.go +++ b/client/internal/netflow/store/event_aggregation_test.go @@ -17,22 +17,32 @@ func TestFlowAggregation(t *testing.T) { var protocols = []types.Protocol{types.ICMP, types.ICMPv6, types.TCP, types.UDP} var tests = []struct { description string + addresses [][]netip.Addr + dstPort uint16 eventTypes []types.Type }{ { description: "start and stop", + addresses: [][]netip.Addr{{ipAddr("1.1.1.1"), ipAddr("2.2.2.2")}, {ipAddr("3.3.3.3"), ipAddr("2.2.2.2")}}, + dstPort: uint16(random.Uint32() >> 16), eventTypes: []types.Type{types.TypeStart, types.TypeEnd}, }, { description: "start and drop", + addresses: [][]netip.Addr{{ipAddr("1.1.1.1"), ipAddr("2.2.2.2")}, {ipAddr("3.3.3.3"), ipAddr("2.2.2.2")}}, + dstPort: uint16(random.Uint32() >> 16), eventTypes: []types.Type{types.TypeStart, types.TypeDrop}, }, { description: "start only", + addresses: [][]netip.Addr{{ipAddr("1.1.1.1"), ipAddr("2.2.2.2")}, {ipAddr("3.3.3.3"), ipAddr("2.2.2.2")}}, + dstPort: uint16(random.Uint32() >> 16), eventTypes: []types.Type{types.TypeStart}, }, { description: "drop only", + addresses: [][]netip.Addr{{ipAddr("1.1.1.1"), ipAddr("2.2.2.2")}, {ipAddr("3.3.3.3"), ipAddr("2.2.2.2")}}, + dstPort: uint16(random.Uint32() >> 16), eventTypes: []types.Type{types.TypeDrop}, }} @@ -42,8 +52,8 @@ func TestFlowAggregation(t *testing.T) { store := NewAggregatingMemoryStore() allExpected := make([]*types.Event, 0) - for i := 0; i < 2; i++ { - inEvents, expected := generateEvents(tt.eventTypes, protocol, types.Ingress, 0) + for _, srcAndDst := range tt.addresses { + inEvents, expected := generateEvents(srcAndDst[0], srcAndDst[1], tt.dstPort, tt.eventTypes, protocol, types.Ingress, 0) for _, e := range inEvents { store.StoreEvent(e) } @@ -63,22 +73,27 @@ func TestIcmpEventAggregation(t *testing.T) { var tests = []struct { description string + addresses [][]netip.Addr eventTypes []types.Type }{ { description: "start and stop", + addresses: [][]netip.Addr{{ipAddr("1.1.1.1"), ipAddr("2.2.2.2")}}, eventTypes: []types.Type{types.TypeStart, types.TypeEnd}, }, { description: "start and drop", + addresses: [][]netip.Addr{{ipAddr("1.1.1.1"), ipAddr("2.2.2.2")}}, eventTypes: []types.Type{types.TypeStart, types.TypeDrop}, }, { description: "start only", + addresses: [][]netip.Addr{{ipAddr("1.1.1.1"), ipAddr("2.2.2.2")}}, eventTypes: []types.Type{types.TypeStart}, }, { description: "drop only", + addresses: [][]netip.Addr{{ipAddr("1.1.1.1"), ipAddr("2.2.2.2")}}, eventTypes: []types.Type{types.TypeDrop}, }} @@ -88,7 +103,7 @@ func TestIcmpEventAggregation(t *testing.T) { store := NewAggregatingMemoryStore() allExpected := make([]*types.Event, 0) for _, icmpType := range icmpTypes { - events, expected := generateEvents(tt.eventTypes, protocol, types.Ingress, icmpType) + events, expected := generateEvents(tt.addresses[0][0], tt.addresses[0][1], 0, tt.eventTypes, protocol, types.Ingress, icmpType) for _, e := range events { store.StoreEvent(e) } @@ -107,15 +122,12 @@ func ipAddr(a string) netip.Addr { return addr } -func generateEvents(eventTypes []types.Type, protocol types.Protocol, direction types.Direction, icmpType uint8) ([]*types.Event, *types.Event) { +func generateEvents(srcIp, dstIp netip.Addr, dstPort uint16, eventTypes []types.Type, protocol types.Protocol, direction types.Direction, icmpType uint8) ([]*types.Event, *types.Event) { var rxPackets, txPackets, rxBytes, txBytes uint64 inEvents := make([]*types.Event, 0) ts := time.Now() flowId := uuid.New() - srcIp := ipAddr("1.1.1.1") srcPort := uint16(random.Uint32() >> 16) - dstIp := ipAddr("2.2.2.2") - dstPort := uint16(random.Uint32() >> 16) for idx, eventType := range eventTypes { e := &types.Event{ diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index 1a3b9227a7a..9cc5edd230e 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -71,17 +71,22 @@ func (am *AggregatingMemory) ResetAggregationWindow() types.FlowEventAggregator } type aggregationKey struct { - destAddr netip.Addr - destPort uint16 - protocol uint8 - icmpType uint8 - unique int64 // used to prevent aggregation on non icmp/udp/tcp events + srcAddr netip.Addr + destAddr netip.Addr + destPort uint16 + direction int + protocol uint8 + icmpType uint8 + unique int64 // used to prevent aggregation on non icmp/udp/tcp events } func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { + am.mux.Lock() + defer am.mux.Unlock() + aggregated := make(map[aggregationKey]*types.Event) for _, v := range am.events { - lookupKey := aggregationKey{destAddr: v.DestIP, destPort: v.DestPort, protocol: uint8(v.Protocol), icmpType: v.ICMPType} + lookupKey := aggregationKey{srcAddr: v.SourceIP, destAddr: v.DestIP, destPort: v.DestPort, direction: int(v.Direction), protocol: uint8(v.Protocol), icmpType: v.ICMPType} if _, ok := aggregated[lookupKey]; !ok { aggregated[lookupKey] = v.Clone() event := aggregated[lookupKey] From 7295e2e51f6b217935dd2384a92a72a57e76a716 Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Tue, 16 Jun 2026 15:47:38 +0200 Subject: [PATCH 17/30] fixed an issue with how we track events that shouldn't be aggregated Signed-off-by: Dmitri Dolguikh --- client/internal/netflow/store/memory.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index 9cc5edd230e..d7e06e8c327 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -88,13 +88,14 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { for _, v := range am.events { lookupKey := aggregationKey{srcAddr: v.SourceIP, destAddr: v.DestIP, destPort: v.DestPort, direction: int(v.Direction), protocol: uint8(v.Protocol), icmpType: v.ICMPType} if _, ok := aggregated[lookupKey]; !ok { - aggregated[lookupKey] = v.Clone() - event := aggregated[lookupKey] + event := v.Clone() if event.Protocol != types.ICMP && event.Protocol != types.ICMPv6 && event.Protocol != types.UDP && event.Protocol != types.TCP { lookupKey.unique = time.Now().UnixNano() // to make the lookup key unique so we don't aggregate on it + aggregated[lookupKey] = event continue } + aggregated[lookupKey] = event switch event.Type { case types.TypeStart: @@ -104,6 +105,10 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { case types.TypeEnd: event.NumOfEnds += 1 } + + if event.Protocol == types.ICMP || event.Protocol == types.ICMPv6 { + event.ICMPCode = 0 // reset icmp code + } continue } @@ -130,7 +135,6 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { aggregatedEvent.ID = v.ID aggregatedEvent.Type = v.Type } - // do we aggregate icmp by code? } return slices.Collect(maps.Values(aggregated)) // could return an iterator instead here From 67d14198747090260447fb0cc2d3faf13089e998 Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Tue, 16 Jun 2026 15:53:53 +0200 Subject: [PATCH 18/30] fixed mapping of events to protobuf Signed-off-by: Dmitri Dolguikh --- client/internal/netflow/manager.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/internal/netflow/manager.go b/client/internal/netflow/manager.go index 570ecc7a968..b26455141d9 100644 --- a/client/internal/netflow/manager.go +++ b/client/internal/netflow/manager.go @@ -314,6 +314,9 @@ func toProtoEvent(publicKey []byte, event *nftypes.Event) *proto.FlowEvent { TxBytes: event.TxBytes, SourceResourceId: event.SourceResourceID, DestResourceId: event.DestResourceID, + NumOfStarts: event.NumOfStarts, + NumOfEnds: event.NumOfEnds, + NumOfDrops: event.NumOfDrops, }, } From ca4ce0a639247a8d610ead99148ecdba812e98c5 Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Tue, 16 Jun 2026 16:01:07 +0200 Subject: [PATCH 19/30] icmp code values in aggregated events do not matter Signed-off-by: Dmitri Dolguikh --- client/internal/netflow/store/memory.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index d7e06e8c327..6a01c904f9a 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -106,9 +106,9 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { event.NumOfEnds += 1 } - if event.Protocol == types.ICMP || event.Protocol == types.ICMPv6 { - event.ICMPCode = 0 // reset icmp code - } + // Please note that ICMPCode field isn't propagated by the manager (see flow/proto/flow.pb.go, FlowFields struct) + // so the field value in an icmp event in the "aggregated" doesn't matter + continue } From 0286c17ad643a349b7ed92ca19b9686db9b79587 Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Tue, 16 Jun 2026 16:15:31 +0200 Subject: [PATCH 20/30] regenerate openapi types Signed-off-by: Dmitri Dolguikh --- shared/management/http/api/types.gen.go | 139 +++++++++++++++++++++++- 1 file changed, 137 insertions(+), 2 deletions(-) diff --git a/shared/management/http/api/types.gen.go b/shared/management/http/api/types.gen.go index e1a4399c40d..3300e004c99 100644 --- a/shared/management/http/api/types.gen.go +++ b/shared/management/http/api/types.gen.go @@ -959,6 +959,30 @@ func (e SentinelOneMatchAttributesNetworkStatus) Valid() bool { } } +// Defines values for ServiceMode. +const ( + ServiceModeHttp ServiceMode = "http" + ServiceModeTcp ServiceMode = "tcp" + ServiceModeTls ServiceMode = "tls" + ServiceModeUdp ServiceMode = "udp" +) + +// Valid indicates whether the value is a known member of the ServiceMode enum. +func (e ServiceMode) Valid() bool { + switch e { + case ServiceModeHttp: + return true + case ServiceModeTcp: + return true + case ServiceModeTls: + return true + case ServiceModeUdp: + return true + default: + return false + } +} + // Defines values for ServiceMetaStatus. const ( ServiceMetaStatusActive ServiceMetaStatus = "active" @@ -989,6 +1013,30 @@ func (e ServiceMetaStatus) Valid() bool { } } +// Defines values for ServiceRequestMode. +const ( + ServiceRequestModeHttp ServiceRequestMode = "http" + ServiceRequestModeTcp ServiceRequestMode = "tcp" + ServiceRequestModeTls ServiceRequestMode = "tls" + ServiceRequestModeUdp ServiceRequestMode = "udp" +) + +// Valid indicates whether the value is a known member of the ServiceRequestMode enum. +func (e ServiceRequestMode) Valid() bool { + switch e { + case ServiceRequestModeHttp: + return true + case ServiceRequestModeTcp: + return true + case ServiceRequestModeTls: + return true + case ServiceRequestModeUdp: + return true + default: + return false + } +} + // Defines values for ServiceTargetProtocol. const ( ServiceTargetProtocolHttp ServiceTargetProtocol = "http" @@ -4054,7 +4102,57 @@ type SentinelOneMatchAttributes struct { type SentinelOneMatchAttributesNetworkStatus string // Service defines model for Service. -type Service = interface{} +type Service struct { + // AccessGroups NetBird group IDs whose peers may reach this private service over the tunnel. Required when private=true; ignored otherwise. Mutually exclusive with bearer auth (SSO). + AccessGroups *[]string `json:"access_groups,omitempty"` + + // AccessRestrictions Connection-level access restrictions based on IP address or geography. Applies to both HTTP and L4 services. + AccessRestrictions *AccessRestrictions `json:"access_restrictions,omitempty"` + Auth ServiceAuthConfig `json:"auth"` + + // Domain Domain for the service + Domain string `json:"domain"` + + // Enabled Whether the service is enabled + Enabled bool `json:"enabled"` + + // Id Service ID + Id string `json:"id"` + + // ListenPort Port the proxy listens on (L4/TLS only) + ListenPort *int `json:"listen_port,omitempty"` + Meta ServiceMeta `json:"meta"` + + // Mode Service mode. "http" for L7 reverse proxy, "tcp"/"udp"/"tls" for L4 passthrough. + Mode *ServiceMode `json:"mode,omitempty"` + + // Name Service name + Name string `json:"name"` + + // PassHostHeader When true, the original client Host header is passed through to the backend instead of being rewritten to the backend's address + PassHostHeader *bool `json:"pass_host_header,omitempty"` + + // PortAutoAssigned Whether the listen port was auto-assigned + PortAutoAssigned *bool `json:"port_auto_assigned,omitempty"` + + // Private When true, the service is NetBird-only — its target points at a proxy cluster, inbound peers authenticate via their WireGuard tunnel identity (no OIDC), and an ACL policy is auto-generated from access_groups to the cluster's proxy-peer group. Requires mode=http. + Private *bool `json:"private,omitempty"` + + // ProxyCluster The proxy cluster handling this service (derived from domain) + ProxyCluster *string `json:"proxy_cluster,omitempty"` + + // RewriteRedirects When true, Location headers in backend responses are rewritten to replace the backend address with the public-facing domain + RewriteRedirects *bool `json:"rewrite_redirects,omitempty"` + + // Targets List of target backends for this service + Targets []ServiceTarget `json:"targets"` + + // Terminated Whether the service has been terminated. Terminated services cannot be updated. Services that violate the Terms of Service will be terminated. + Terminated *bool `json:"terminated,omitempty"` +} + +// ServiceMode Service mode. "http" for L7 reverse proxy, "tcp"/"udp"/"tls" for L4 passthrough. +type ServiceMode string // ServiceAuthConfig defines model for ServiceAuthConfig. type ServiceAuthConfig struct { @@ -4081,7 +4179,44 @@ type ServiceMeta struct { type ServiceMetaStatus string // ServiceRequest defines model for ServiceRequest. -type ServiceRequest = interface{} +type ServiceRequest struct { + // AccessGroups NetBird group IDs whose peers may reach this private service over the tunnel. Required when private=true; ignored otherwise. Mutually exclusive with bearer auth (SSO). + AccessGroups *[]string `json:"access_groups,omitempty"` + + // AccessRestrictions Connection-level access restrictions based on IP address or geography. Applies to both HTTP and L4 services. + AccessRestrictions *AccessRestrictions `json:"access_restrictions,omitempty"` + Auth *ServiceAuthConfig `json:"auth,omitempty"` + + // Domain Domain for the service + Domain string `json:"domain"` + + // Enabled Whether the service is enabled + Enabled bool `json:"enabled"` + + // ListenPort Port the proxy listens on (L4/TLS only). Set to 0 for auto-assignment. + ListenPort *int `json:"listen_port,omitempty"` + + // Mode Service mode. "http" for L7 reverse proxy, "tcp"/"udp"/"tls" for L4 passthrough. + Mode *ServiceRequestMode `json:"mode,omitempty"` + + // Name Service name + Name string `json:"name"` + + // PassHostHeader When true, the original client Host header is passed through to the backend instead of being rewritten to the backend's address + PassHostHeader *bool `json:"pass_host_header,omitempty"` + + // Private When true, the service is NetBird-only — its target points at a proxy cluster, inbound peers authenticate via their WireGuard tunnel identity (no OIDC), and an ACL policy is auto-generated from access_groups to the cluster's proxy-peer group. Requires mode=http. + Private *bool `json:"private,omitempty"` + + // RewriteRedirects When true, Location headers in backend responses are rewritten to replace the backend address with the public-facing domain + RewriteRedirects *bool `json:"rewrite_redirects,omitempty"` + + // Targets List of target backends for this service + Targets *[]ServiceTarget `json:"targets,omitempty"` +} + +// ServiceRequestMode Service mode. "http" for L7 reverse proxy, "tcp"/"udp"/"tls" for L4 passthrough. +type ServiceRequestMode string // ServiceTarget defines model for ServiceTarget. type ServiceTarget struct { From 3d6fc3bf9248b86303ed8295c71684c1d9c51c70 Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Tue, 16 Jun 2026 16:20:10 +0200 Subject: [PATCH 21/30] added a comment re: unbounded unacked events Signed-off-by: Dmitri Dolguikh --- client/internal/netflow/manager.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/internal/netflow/manager.go b/client/internal/netflow/manager.go index b26455141d9..fa66fcf32e8 100644 --- a/client/internal/netflow/manager.go +++ b/client/internal/netflow/manager.go @@ -248,6 +248,8 @@ func (m *Manager) receiveACKs(ctx context.Context, client *client.GRPCClient) { } } +// We effectively never drop events (see MaxInterval), which makes eventsWithoutAcks unbounded. +// We may want to limit the max size of the store, and start dropping oldest events when the threshold is reached. func (m *Manager) startRetries(ctx context.Context) { timer := time.NewTimer(m.retryInterval) retryBackoff := backoff.WithContext(&backoff.ExponentialBackOff{ From 9ea463ec2eb4102e02978e718f61df90218588e5 Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Tue, 16 Jun 2026 16:45:40 +0200 Subject: [PATCH 22/30] reset aggregated event type to unknown Signed-off-by: Dmitri Dolguikh --- client/internal/netflow/store/memory.go | 1 + 1 file changed, 1 insertion(+) diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index 6a01c904f9a..fa2a0a3e1f2 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -105,6 +105,7 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { case types.TypeEnd: event.NumOfEnds += 1 } + event.Type = types.TypeUnknown // Please note that ICMPCode field isn't propagated by the manager (see flow/proto/flow.pb.go, FlowFields struct) // so the field value in an icmp event in the "aggregated" doesn't matter From 1721a4ff7df253644e037342e70df2a3bb6067aa Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Tue, 16 Jun 2026 17:03:49 +0200 Subject: [PATCH 23/30] fix event aggregation test Signed-off-by: Dmitri Dolguikh --- client/internal/netflow/store/event_aggregation_test.go | 2 +- client/internal/netflow/store/memory.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/client/internal/netflow/store/event_aggregation_test.go b/client/internal/netflow/store/event_aggregation_test.go index 8064e0e4a2e..411177331df 100644 --- a/client/internal/netflow/store/event_aggregation_test.go +++ b/client/internal/netflow/store/event_aggregation_test.go @@ -176,7 +176,7 @@ func generateEvents(srcIp, dstIp netip.Addr, dstPort uint16, eventTypes []types. Timestamp: inEvents[0].Timestamp, EventFields: types.EventFields{ FlowID: flowId, - Type: inEvents[0].Type, + Type: types.TypeUnknown, Protocol: inEvents[0].Protocol, RuleID: []byte("rule-id-1"), Direction: inEvents[0].Direction, diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index fa2a0a3e1f2..b264bfd4a66 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -134,7 +134,6 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { if aggregatedEvent.Timestamp.Compare(v.Timestamp) > 0 { aggregatedEvent.Timestamp = v.Timestamp aggregatedEvent.ID = v.ID - aggregatedEvent.Type = v.Type } } From 5dc159e06ae54f23406397757795b706e2d14f52 Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Tue, 16 Jun 2026 17:16:27 +0200 Subject: [PATCH 24/30] used the source port of the earliest event Signed-off-by: Dmitri Dolguikh --- client/internal/netflow/store/memory.go | 1 + 1 file changed, 1 insertion(+) diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index b264bfd4a66..6f689b695d0 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -134,6 +134,7 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { if aggregatedEvent.Timestamp.Compare(v.Timestamp) > 0 { aggregatedEvent.Timestamp = v.Timestamp aggregatedEvent.ID = v.ID + aggregatedEvent.SourcePort = v.SourcePort } } From 0e95b6d1c9ab8cd9fd20f4963fee40b621777f5f Mon Sep 17 00:00:00 2001 From: Dmitri Date: Mon, 15 Jun 2026 17:32:35 +0200 Subject: [PATCH 25/30] add tracking of window starts and ends Signed-off-by: Dmitri Dolguikh --- client/internal/netflow/manager.go | 8 +- .../netflow/store/event_aggregation_test.go | 17 +- client/internal/netflow/store/memory.go | 10 +- client/internal/netflow/types/types.go | 6 +- flow/proto/flow.pb.go | 193 ++++++++++-------- flow/proto/flow.proto | 3 + flow/proto/flow_grpc.pb.go | 7 +- 7 files changed, 147 insertions(+), 97 deletions(-) diff --git a/client/internal/netflow/manager.go b/client/internal/netflow/manager.go index fa66fcf32e8..b1d0afecb60 100644 --- a/client/internal/netflow/manager.go +++ b/client/internal/netflow/manager.go @@ -299,9 +299,11 @@ func (m *Manager) send(event *nftypes.Event) error { func toProtoEvent(publicKey []byte, event *nftypes.Event) *proto.FlowEvent { protoEvent := &proto.FlowEvent{ - EventId: event.ID[:], - Timestamp: timestamppb.New(event.Timestamp), - PublicKey: publicKey, + EventId: event.ID[:], + Timestamp: timestamppb.New(event.Timestamp), + PublicKey: publicKey, + WindowStart: timestamppb.New(event.WindowStart), + WindowEnd: timestamppb.New(event.WindowEnd), FlowFields: &proto.FlowFields{ FlowId: event.FlowID[:], RuleId: event.RuleID, diff --git a/client/internal/netflow/store/event_aggregation_test.go b/client/internal/netflow/store/event_aggregation_test.go index 411177331df..3bd1b21ea9e 100644 --- a/client/internal/netflow/store/event_aggregation_test.go +++ b/client/internal/netflow/store/event_aggregation_test.go @@ -50,10 +50,12 @@ func TestFlowAggregation(t *testing.T) { for _, tt := range tests { t.Run(tt.description+" "+protocol.String(), func(t *testing.T) { store := NewAggregatingMemoryStore() + store.WindowEnd = time.Now().Add(5 * time.Second) + allExpected := make([]*types.Event, 0) for _, srcAndDst := range tt.addresses { - inEvents, expected := generateEvents(srcAndDst[0], srcAndDst[1], tt.dstPort, tt.eventTypes, protocol, types.Ingress, 0) + inEvents, expected := generateEvents(srcAndDst[0], srcAndDst[1], tt.dstPort, tt.eventTypes, protocol, types.Ingress, 0, store.WindowStart, store.WindowEnd) for _, e := range inEvents { store.StoreEvent(e) } @@ -101,9 +103,11 @@ func TestIcmpEventAggregation(t *testing.T) { for _, tt := range tests { t.Run(tt.description+" "+protocol.String(), func(t *testing.T) { store := NewAggregatingMemoryStore() + store.WindowEnd = time.Now().Add(5 * time.Second) + allExpected := make([]*types.Event, 0) for _, icmpType := range icmpTypes { - events, expected := generateEvents(tt.addresses[0][0], tt.addresses[0][1], 0, tt.eventTypes, protocol, types.Ingress, icmpType) + events, expected := generateEvents(tt.addresses[0][0], tt.addresses[0][1], 0, tt.eventTypes, protocol, types.Ingress, icmpType, store.WindowStart, store.WindowEnd) for _, e := range events { store.StoreEvent(e) } @@ -122,7 +126,8 @@ func ipAddr(a string) netip.Addr { return addr } -func generateEvents(srcIp, dstIp netip.Addr, dstPort uint16, eventTypes []types.Type, protocol types.Protocol, direction types.Direction, icmpType uint8) ([]*types.Event, *types.Event) { +func generateEvents(srcIp, dstIp netip.Addr, dstPort uint16, eventTypes []types.Type, protocol types.Protocol, + direction types.Direction, icmpType uint8, windowStart, windowEnd time.Time) ([]*types.Event, *types.Event) { var rxPackets, txPackets, rxBytes, txBytes uint64 inEvents := make([]*types.Event, 0) ts := time.Now() @@ -172,8 +177,10 @@ func generateEvents(srcIp, dstIp netip.Addr, dstPort uint16, eventTypes []types. } } aggregatedEvent := &types.Event{ - ID: inEvents[0].ID, - Timestamp: inEvents[0].Timestamp, + ID: inEvents[0].ID, + Timestamp: inEvents[0].Timestamp, + WindowStart: windowStart, + WindowEnd: windowEnd, EventFields: types.EventFields{ FlowID: flowId, Type: types.TypeUnknown, diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index 6f689b695d0..02fe8890300 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -24,6 +24,8 @@ type Memory struct { type AggregatingMemory struct { Memory + WindowStart time.Time + WindowEnd time.Time } func (m *Memory) StoreEvent(event *types.Event) { @@ -57,15 +59,17 @@ func (m *Memory) DeleteEvents(ids []uuid.UUID) { } func NewAggregatingMemoryStore() *AggregatingMemory { - return &AggregatingMemory{Memory{events: make(map[uuid.UUID]*types.Event)}} + return &AggregatingMemory{WindowStart: time.Now(), Memory: Memory{events: make(map[uuid.UUID]*types.Event)}} } func (am *AggregatingMemory) ResetAggregationWindow() types.FlowEventAggregator { am.mux.Lock() defer am.mux.Unlock() - toret := AggregatingMemory{Memory: Memory{events: am.events}} + toret := AggregatingMemory{WindowStart: am.WindowStart, WindowEnd: time.Now(), Memory: Memory{events: am.events}} + am.events = make(map[uuid.UUID]*types.Event) + am.WindowStart = time.Now() return &toret } @@ -110,6 +114,8 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { // Please note that ICMPCode field isn't propagated by the manager (see flow/proto/flow.pb.go, FlowFields struct) // so the field value in an icmp event in the "aggregated" doesn't matter + event.WindowStart = am.WindowStart + event.WindowEnd = am.WindowEnd continue } diff --git a/client/internal/netflow/types/types.go b/client/internal/netflow/types/types.go index d0952fd2c58..ccb2da66bf9 100644 --- a/client/internal/netflow/types/types.go +++ b/client/internal/netflow/types/types.go @@ -70,8 +70,10 @@ const ( ) type Event struct { - ID uuid.UUID - Timestamp time.Time + ID uuid.UUID + Timestamp time.Time + WindowStart time.Time + WindowEnd time.Time EventFields } diff --git a/flow/proto/flow.pb.go b/flow/proto/flow.pb.go index b9f0d7b94c2..710024f0eb4 100644 --- a/flow/proto/flow.pb.go +++ b/flow/proto/flow.pb.go @@ -134,9 +134,11 @@ type FlowEvent struct { // When the event occurred Timestamp *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Public key of the sending peer - PublicKey []byte `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` - FlowFields *FlowFields `protobuf:"bytes,4,opt,name=flow_fields,json=flowFields,proto3" json:"flow_fields,omitempty"` - IsInitiator bool `protobuf:"varint,5,opt,name=isInitiator,proto3" json:"isInitiator,omitempty"` + PublicKey []byte `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + FlowFields *FlowFields `protobuf:"bytes,4,opt,name=flow_fields,json=flowFields,proto3" json:"flow_fields,omitempty"` + IsInitiator bool `protobuf:"varint,5,opt,name=isInitiator,proto3" json:"isInitiator,omitempty"` + WindowStart *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=window_start,json=windowStart,proto3" json:"window_start,omitempty"` + WindowEnd *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=window_end,json=windowEnd,proto3" json:"window_end,omitempty"` } func (x *FlowEvent) Reset() { @@ -206,6 +208,20 @@ func (x *FlowEvent) GetIsInitiator() bool { return false } +func (x *FlowEvent) GetWindowStart() *timestamppb.Timestamp { + if x != nil { + return x.WindowStart + } + return nil +} + +func (x *FlowEvent) GetWindowEnd() *timestamppb.Timestamp { + if x != nil { + return x.WindowEnd + } + return nil +} + type FlowEventAck struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -602,7 +618,7 @@ var file_flow_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x66, 0x6c, 0x6f, 0x77, 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, 0x22, 0xd4, 0x01, 0x0a, 0x09, 0x46, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, + 0x6f, 0x74, 0x6f, 0x22, 0xce, 0x02, 0x0a, 0x09, 0x46, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, @@ -615,75 +631,82 @@ var file_flow_proto_rawDesc = []byte{ 0x77, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x52, 0x0a, 0x66, 0x6c, 0x6f, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, - 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x4b, 0x0a, 0x0c, 0x46, 0x6c, - 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, - 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x49, 0x6e, - 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x82, 0x05, 0x0a, 0x0a, 0x46, 0x6c, 0x6f, 0x77, - 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x12, - 0x1e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, - 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, - 0x17, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x06, 0x72, 0x75, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x66, 0x6c, - 0x6f, 0x77, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, - 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x70, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x70, - 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x06, 0x64, 0x65, 0x73, 0x74, 0x49, 0x70, 0x12, 0x2d, 0x0a, 0x09, 0x70, 0x6f, 0x72, - 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x66, - 0x6c, 0x6f, 0x77, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x08, - 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2d, 0x0a, 0x09, 0x69, 0x63, 0x6d, 0x70, - 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x66, 0x6c, - 0x6f, 0x77, 0x2e, 0x49, 0x43, 0x4d, 0x50, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x08, 0x69, - 0x63, 0x6d, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x78, 0x5f, 0x70, 0x61, - 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x78, 0x50, - 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x78, 0x5f, 0x70, 0x61, 0x63, - 0x6b, 0x65, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x78, 0x50, 0x61, - 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x78, 0x5f, 0x62, 0x79, 0x74, 0x65, - 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x72, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, - 0x12, 0x19, 0x0a, 0x08, 0x74, 0x78, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x07, 0x74, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, - 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x73, - 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0f, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x4f, - 0x66, 0x53, 0x74, 0x61, 0x72, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, - 0x66, 0x5f, 0x65, 0x6e, 0x64, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6e, 0x75, - 0x6d, 0x4f, 0x66, 0x45, 0x6e, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, - 0x66, 0x5f, 0x64, 0x72, 0x6f, 0x70, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6e, - 0x75, 0x6d, 0x4f, 0x66, 0x44, 0x72, 0x6f, 0x70, 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x48, 0x0a, 0x08, - 0x50, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x73, - 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, - 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x22, 0x44, 0x0a, 0x08, 0x49, 0x43, 0x4d, 0x50, 0x49, 0x6e, - 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x63, 0x6d, 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x69, 0x63, 0x6d, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x1b, 0x0a, 0x09, 0x69, 0x63, 0x6d, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x08, 0x69, 0x63, 0x6d, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x2a, 0x45, 0x0a, 0x04, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, - 0x54, 0x41, 0x52, 0x54, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, - 0x4e, 0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x52, 0x4f, - 0x50, 0x10, 0x03, 0x2a, 0x3b, 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x15, 0x0a, 0x11, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, - 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x47, 0x52, 0x45, - 0x53, 0x53, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x02, - 0x32, 0x42, 0x0a, 0x0b, 0x46, 0x6c, 0x6f, 0x77, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x33, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x0f, 0x2e, 0x66, 0x6c, 0x6f, 0x77, - 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x12, 0x2e, 0x66, 0x6c, 0x6f, - 0x77, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x22, 0x00, - 0x28, 0x01, 0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x3d, 0x0a, 0x0c, 0x77, 0x69, + 0x6e, 0x64, 0x6f, 0x77, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x06, 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, 0x0b, 0x77, 0x69, + 0x6e, 0x64, 0x6f, 0x77, 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x77, 0x69, 0x6e, + 0x64, 0x6f, 0x77, 0x5f, 0x65, 0x6e, 0x64, 0x18, 0x07, 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, 0x09, 0x77, 0x69, 0x6e, 0x64, 0x6f, + 0x77, 0x45, 0x6e, 0x64, 0x22, 0x4b, 0x0a, 0x0c, 0x46, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x41, 0x63, 0x6b, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, + 0x20, 0x0a, 0x0b, 0x69, 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, + 0x72, 0x22, 0x82, 0x05, 0x0a, 0x0a, 0x46, 0x6c, 0x6f, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, + 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x54, + 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x75, 0x6c, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x75, 0x6c, 0x65, + 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x44, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1b, 0x0a, + 0x09, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x08, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x70, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, + 0x73, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x64, 0x65, 0x73, + 0x74, 0x49, 0x70, 0x12, 0x2d, 0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x50, 0x6f, + 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x2d, 0x0a, 0x09, 0x69, 0x63, 0x6d, 0x70, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x43, 0x4d, + 0x50, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x08, 0x69, 0x63, 0x6d, 0x70, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x78, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x78, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, + 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x78, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x78, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, + 0x19, 0x0a, 0x08, 0x72, 0x78, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x07, 0x72, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x78, + 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x78, + 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x64, + 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x22, 0x0a, + 0x0d, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x18, 0x10, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x65, 0x6e, 0x64, 0x73, + 0x18, 0x11, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x45, 0x6e, 0x64, + 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x64, 0x72, 0x6f, 0x70, + 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x44, 0x72, + 0x6f, 0x70, 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x48, 0x0a, 0x08, 0x50, 0x6f, 0x72, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x6f, 0x72, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, + 0x6f, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, 0x73, 0x74, 0x50, 0x6f, 0x72, 0x74, + 0x22, 0x44, 0x0a, 0x08, 0x49, 0x43, 0x4d, 0x50, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, + 0x69, 0x63, 0x6d, 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x08, 0x69, 0x63, 0x6d, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x63, 0x6d, + 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x69, 0x63, + 0x6d, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x2a, 0x45, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, + 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, + 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x01, + 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, 0x44, 0x10, 0x02, 0x12, 0x0d, + 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x52, 0x4f, 0x50, 0x10, 0x03, 0x2a, 0x3b, 0x0a, + 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x44, 0x49, + 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, + 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x0a, + 0x0a, 0x06, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x02, 0x32, 0x42, 0x0a, 0x0b, 0x46, 0x6c, + 0x6f, 0x77, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x12, 0x0f, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x12, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x46, 0x6c, 0x6f, 0x77, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x08, + 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -713,17 +736,19 @@ var file_flow_proto_goTypes = []interface{}{ var file_flow_proto_depIdxs = []int32{ 7, // 0: flow.FlowEvent.timestamp:type_name -> google.protobuf.Timestamp 4, // 1: flow.FlowEvent.flow_fields:type_name -> flow.FlowFields - 0, // 2: flow.FlowFields.type:type_name -> flow.Type - 1, // 3: flow.FlowFields.direction:type_name -> flow.Direction - 5, // 4: flow.FlowFields.port_info:type_name -> flow.PortInfo - 6, // 5: flow.FlowFields.icmp_info:type_name -> flow.ICMPInfo - 2, // 6: flow.FlowService.Events:input_type -> flow.FlowEvent - 3, // 7: flow.FlowService.Events:output_type -> flow.FlowEventAck - 7, // [7:8] is the sub-list for method output_type - 6, // [6:7] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 7, // 2: flow.FlowEvent.window_start:type_name -> google.protobuf.Timestamp + 7, // 3: flow.FlowEvent.window_end:type_name -> google.protobuf.Timestamp + 0, // 4: flow.FlowFields.type:type_name -> flow.Type + 1, // 5: flow.FlowFields.direction:type_name -> flow.Direction + 5, // 6: flow.FlowFields.port_info:type_name -> flow.PortInfo + 6, // 7: flow.FlowFields.icmp_info:type_name -> flow.ICMPInfo + 2, // 8: flow.FlowService.Events:input_type -> flow.FlowEvent + 3, // 9: flow.FlowService.Events:output_type -> flow.FlowEventAck + 9, // [9:10] is the sub-list for method output_type + 8, // [8:9] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_flow_proto_init() } diff --git a/flow/proto/flow.proto b/flow/proto/flow.proto index ec207d2f0ef..1c9e728d28b 100644 --- a/flow/proto/flow.proto +++ b/flow/proto/flow.proto @@ -24,6 +24,9 @@ message FlowEvent { FlowFields flow_fields = 4; bool isInitiator = 5; + + google.protobuf.Timestamp window_start = 6; + google.protobuf.Timestamp window_end = 7; } message FlowEventAck { diff --git a/flow/proto/flow_grpc.pb.go b/flow/proto/flow_grpc.pb.go index 6d9a392d053..9ae9702a5aa 100644 --- a/flow/proto/flow_grpc.pb.go +++ b/flow/proto/flow_grpc.pb.go @@ -1,8 +1,13 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.1 +// - protoc v3.21.9 +// source: flow.proto + package proto import ( context "context" - grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" From fd763ec0dd807bb84918bf06f1b2a18120614f52 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Mon, 15 Jun 2026 18:05:29 +0200 Subject: [PATCH 26/30] updated openapi spec Signed-off-by: Dmitri Dolguikh --- shared/management/http/api/openapi.yml | 15 +++++++++++++++ shared/management/http/api/types.gen.go | 12 +++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/shared/management/http/api/openapi.yml b/shared/management/http/api/openapi.yml index 34088bb5303..461df1b0d80 100644 --- a/shared/management/http/api/openapi.yml +++ b/shared/management/http/api/openapi.yml @@ -2777,6 +2777,16 @@ components: type: integer description: "Number of drop events." example: 5 + window_start: + type: string + format: date-time + description: Timestamp of the start of the aggregation window. + example: 2025-03-20T16:23:58.125397Z + window_end: + type: string + format: date-time + description: Timestamp of the end of the aggregation window. + example: 2025-03-20T16:23:58.125397Z events: type: array description: "List of events that are correlated to this flow (e.g., start, end)." @@ -2798,6 +2808,11 @@ components: - rx_packets - tx_bytes - tx_packets + - num_of_starts + - num_of_ends + - num_of_drops + - window_start + - window_end - events NetworkTrafficEventsResponse: type: object diff --git a/shared/management/http/api/types.gen.go b/shared/management/http/api/types.gen.go index 3300e004c99..844cd4f5958 100644 --- a/shared/management/http/api/types.gen.go +++ b/shared/management/http/api/types.gen.go @@ -2909,13 +2909,13 @@ type NetworkTrafficEvent struct { Icmp NetworkTrafficICMP `json:"icmp"` // NumOfDrops Number of drop events. - NumOfDrops *int `json:"num_of_drops,omitempty"` + NumOfDrops int `json:"num_of_drops"` // NumOfEnds Number of end events. - NumOfEnds *int `json:"num_of_ends,omitempty"` + NumOfEnds int `json:"num_of_ends"` // NumOfStarts Number of start events. - NumOfStarts *int `json:"num_of_starts,omitempty"` + NumOfStarts int `json:"num_of_starts"` Policy NetworkTrafficPolicy `json:"policy"` // Protocol Protocol is the protocol of the traffic (e.g. 1 = ICMP, 6 = TCP, 17 = UDP, etc.). @@ -2937,6 +2937,12 @@ type NetworkTrafficEvent struct { // TxPackets Number of packets transmitted. TxPackets int `json:"tx_packets"` User NetworkTrafficUser `json:"user"` + + // WindowEnd Timestamp of the end of the aggregation window. + WindowEnd time.Time `json:"window_end"` + + // WindowStart Timestamp of the start of the aggregation window. + WindowStart time.Time `json:"window_start"` } // NetworkTrafficEventsResponse defines model for NetworkTrafficEventsResponse. From 17cc13f20f21b4337ecf06eb5a55c9eaa1918c0c Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Wed, 17 Jun 2026 10:26:12 +0200 Subject: [PATCH 27/30] reverted changes to generate.sh Signed-off-by: Dmitri Dolguikh --- flow/proto/generate.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flow/proto/generate.sh b/flow/proto/generate.sh index f2937399a0b..fe447fd7acc 100755 --- a/flow/proto/generate.sh +++ b/flow/proto/generate.sh @@ -12,7 +12,7 @@ old_pwd=$(pwd) script_path=$(dirname $(realpath "$0")) echo "$script_path" cd "$script_path" -#go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26 -#go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1 +go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26 +go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1 protoc -I ./ ./flow.proto --go_out=../ --go-grpc_out=../ cd "$old_pwd" From 41a15f622150eb75d157904b30199bf7951ffe95 Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Mon, 22 Jun 2026 13:16:09 +0200 Subject: [PATCH 28/30] cleanup handling of not-aggregated events + test Signed-off-by: Dmitri Dolguikh --- .../netflow/store/event_aggregation_test.go | 125 ++++++++++++++++++ client/internal/netflow/store/memory.go | 13 +- 2 files changed, 131 insertions(+), 7 deletions(-) diff --git a/client/internal/netflow/store/event_aggregation_test.go b/client/internal/netflow/store/event_aggregation_test.go index 3bd1b21ea9e..dbadef485aa 100644 --- a/client/internal/netflow/store/event_aggregation_test.go +++ b/client/internal/netflow/store/event_aggregation_test.go @@ -121,6 +121,59 @@ func TestIcmpEventAggregation(t *testing.T) { } } +func TestFlowAggregationOfUnknownProtocols(t *testing.T) { + var tests = []struct { + description string + addresses [][]netip.Addr + dstPort uint16 + eventTypes []types.Type + }{ + { + description: "start and stop", + addresses: [][]netip.Addr{{ipAddr("1.1.1.1"), ipAddr("2.2.2.2")}, {ipAddr("3.3.3.3"), ipAddr("2.2.2.2")}}, + dstPort: uint16(random.Uint32() >> 16), + eventTypes: []types.Type{types.TypeStart, types.TypeEnd}, + }, + { + description: "start and drop", + addresses: [][]netip.Addr{{ipAddr("1.1.1.1"), ipAddr("2.2.2.2")}, {ipAddr("3.3.3.3"), ipAddr("2.2.2.2")}}, + dstPort: uint16(random.Uint32() >> 16), + eventTypes: []types.Type{types.TypeStart, types.TypeDrop}, + }, + { + description: "start only", + addresses: [][]netip.Addr{{ipAddr("1.1.1.1"), ipAddr("2.2.2.2")}, {ipAddr("3.3.3.3"), ipAddr("2.2.2.2")}}, + dstPort: uint16(random.Uint32() >> 16), + eventTypes: []types.Type{types.TypeStart}, + }, + { + description: "drop only", + addresses: [][]netip.Addr{{ipAddr("1.1.1.1"), ipAddr("2.2.2.2")}, {ipAddr("3.3.3.3"), ipAddr("2.2.2.2")}}, + dstPort: uint16(random.Uint32() >> 16), + eventTypes: []types.Type{types.TypeDrop}, + }} + + for _, tt := range tests { + t.Run(tt.description+" "+string(types.ProtocolUnknown), func(t *testing.T) { + store := NewAggregatingMemoryStore() + store.WindowEnd = time.Now().Add(5 * time.Second) + + allExpected := make([]*types.Event, 0) + + for _, srcAndDst := range tt.addresses { + inEvents, expected := generateEventsForUnknownProtocol(srcAndDst[0], srcAndDst[1], tt.dstPort, tt.eventTypes, types.ProtocolUnknown, types.Ingress, store.WindowStart, store.WindowEnd) + for _, e := range inEvents { + store.StoreEvent(e) + } + allExpected = append(allExpected, expected...) + } + + events := store.GetAggregatedEvents() + assert.ElementsMatch(t, events, allExpected) + }) + } +} + func ipAddr(a string) netip.Addr { addr, _ := netip.ParseAddr(a) return addr @@ -207,3 +260,75 @@ func generateEvents(srcIp, dstIp netip.Addr, dstPort uint16, eventTypes []types. return inEvents, aggregatedEvent } + +func generateEventsForUnknownProtocol(srcIp, dstIp netip.Addr, dstPort uint16, eventTypes []types.Type, protocol types.Protocol, + direction types.Direction, windowStart, windowEnd time.Time) ([]*types.Event, []*types.Event) { + inEvents := make([]*types.Event, 0) + expectedEvents := make([]*types.Event, 0) + + ts := time.Now() + flowId := uuid.New() + srcPort := uint16(random.Uint32() >> 16) + + for idx, eventType := range eventTypes { + e := &types.Event{ + ID: uuid.New(), + Timestamp: ts.Add(time.Duration(idx) * time.Second), + EventFields: types.EventFields{ + FlowID: flowId, + Type: eventType, + Protocol: protocol, + RuleID: []byte("rule-id-1"), + Direction: direction, + SourceIP: srcIp, + SourcePort: srcPort, + DestIP: dstIp, + DestPort: dstPort, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: random.Uint64(), + TxPackets: random.Uint64(), + RxBytes: random.Uint64(), + TxBytes: random.Uint64(), + }} + inEvents = append(inEvents, e) + + var start, end, drop uint64 + switch eventType { + case types.TypeStart: + start = 1 + case types.TypeDrop: + drop = 1 + case types.TypeEnd: + end = 1 + } + + expectedEvents = append(expectedEvents, &types.Event{ + ID: e.ID, + Timestamp: e.Timestamp, + WindowStart: windowStart, + WindowEnd: windowEnd, + EventFields: types.EventFields{ + FlowID: flowId, + Type: types.TypeUnknown, + Protocol: e.Protocol, + RuleID: []byte("rule-id-1"), + Direction: e.Direction, + SourceIP: srcIp, + SourcePort: srcPort, + DestIP: dstIp, + DestPort: dstPort, + SourceResourceID: []byte("source-resource-id"), + DestResourceID: []byte("dest-resource-id"), + RxPackets: e.RxPackets, + TxPackets: e.TxPackets, + RxBytes: e.RxBytes, + TxBytes: e.TxBytes, + NumOfStarts: start, + NumOfEnds: end, + NumOfDrops: drop, + }}) + } + + return inEvents, expectedEvents +} diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index 02fe8890300..87a2f250b63 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -94,13 +94,6 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { if _, ok := aggregated[lookupKey]; !ok { event := v.Clone() - if event.Protocol != types.ICMP && event.Protocol != types.ICMPv6 && event.Protocol != types.UDP && event.Protocol != types.TCP { - lookupKey.unique = time.Now().UnixNano() // to make the lookup key unique so we don't aggregate on it - aggregated[lookupKey] = event - continue - } - aggregated[lookupKey] = event - switch event.Type { case types.TypeStart: event.NumOfStarts += 1 @@ -116,6 +109,12 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { event.WindowStart = am.WindowStart event.WindowEnd = am.WindowEnd + + if event.Protocol != types.ICMP && event.Protocol != types.ICMPv6 && event.Protocol != types.UDP && event.Protocol != types.TCP { + lookupKey.unique = time.Now().UnixNano() // to make the lookup key unique so we don't aggregate on it + } + + aggregated[lookupKey] = event continue } From 1f1413ec6a93b9f6469d93bcabee8e849d8f6cc5 Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Mon, 22 Jun 2026 18:34:08 +0200 Subject: [PATCH 29/30] responded to feedback + small fixes Signed-off-by: Dmitri Dolguikh --- client/internal/netflow/manager.go | 23 +++++++++++++---------- client/internal/netflow/store/memory.go | 14 +++++++++----- flow/proto/generate.sh | 1 - 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/client/internal/netflow/manager.go b/client/internal/netflow/manager.go index b1d0afecb60..ba07c8522e5 100644 --- a/client/internal/netflow/manager.go +++ b/client/internal/netflow/manager.go @@ -72,6 +72,7 @@ func (m *Manager) needsNewClient(previous *nftypes.FlowConfig) bool { } // enableFlow starts components for flow tracking +// must be called under m.mux lock func (m *Manager) enableFlow(previous *nftypes.FlowConfig) error { // first make sender ready so events don't pile up if m.needsNewClient(previous) { @@ -91,6 +92,7 @@ func (m *Manager) enableFlow(previous *nftypes.FlowConfig) error { return nil } +// must be called under m.mux lock func (m *Manager) resetClient() error { if m.receiverClient != nil { if err := m.receiverClient.Close(); err != nil { @@ -114,17 +116,18 @@ func (m *Manager) resetClient() error { m.cancel = cancel m.shutdownWg.Add(3) + flowConfigInterval := m.flowConfig.Interval go func() { defer m.shutdownWg.Done() - m.receiveACKs(ctx, flowClient) + m.receiveACKs(ctx, flowClient, flowConfigInterval) }() go func() { defer m.shutdownWg.Done() - m.startSender(ctx) + m.startSender(ctx, flowConfigInterval) }() go func() { defer m.shutdownWg.Done() - m.startRetries(ctx) + m.startRetries(ctx, flowConfigInterval) }() return nil @@ -208,8 +211,8 @@ func (m *Manager) GetLogger() nftypes.FlowLogger { return m.logger } -func (m *Manager) startSender(ctx context.Context) { - ticker := time.NewTicker(m.flowConfig.Interval) +func (m *Manager) startSender(ctx context.Context, flowConfigInterval time.Duration) { + ticker := time.NewTicker(flowConfigInterval) defer ticker.Stop() for { @@ -231,8 +234,8 @@ func (m *Manager) startSender(ctx context.Context) { } } -func (m *Manager) receiveACKs(ctx context.Context, client *client.GRPCClient) { - err := client.Receive(ctx, m.flowConfig.Interval, func(ack *proto.FlowEventAck) error { +func (m *Manager) receiveACKs(ctx context.Context, client *client.GRPCClient, flowConfigInterval time.Duration) { + err := client.Receive(ctx, flowConfigInterval, func(ack *proto.FlowEventAck) error { id, err := uuid.FromBytes(ack.EventId) if err != nil { log.Warnf("failed to convert ack event id to uuid: %v", err) @@ -250,13 +253,13 @@ func (m *Manager) receiveACKs(ctx context.Context, client *client.GRPCClient) { // We effectively never drop events (see MaxInterval), which makes eventsWithoutAcks unbounded. // We may want to limit the max size of the store, and start dropping oldest events when the threshold is reached. -func (m *Manager) startRetries(ctx context.Context) { +func (m *Manager) startRetries(ctx context.Context, flowConfigInterval time.Duration) { timer := time.NewTimer(m.retryInterval) retryBackoff := backoff.WithContext(&backoff.ExponentialBackOff{ InitialInterval: 1 * time.Second, RandomizationFactor: 0.5, Multiplier: 1.7, - MaxInterval: m.flowConfig.Interval / 2, + MaxInterval: flowConfigInterval / 2, MaxElapsedTime: 3 * 30 * 24 * time.Hour, // 3 months Stop: backoff.Stop, Clock: backoff.SystemClock, @@ -280,7 +283,7 @@ func (m *Manager) startRetries(ctx context.Context) { } } retryBackoff.Reset() - timer = time.NewTimer(time.Second) + timer = time.NewTimer(m.retryInterval) } } } diff --git a/client/internal/netflow/store/memory.go b/client/internal/netflow/store/memory.go index 87a2f250b63..aba2c6e48f1 100644 --- a/client/internal/netflow/store/memory.go +++ b/client/internal/netflow/store/memory.go @@ -2,6 +2,8 @@ package store import ( "maps" + "math/rand" + v2 "math/rand/v2" "net/netip" "slices" "sync" @@ -26,6 +28,7 @@ type AggregatingMemory struct { Memory WindowStart time.Time WindowEnd time.Time + rnd *v2.PCG } func (m *Memory) StoreEvent(event *types.Event) { @@ -59,17 +62,18 @@ func (m *Memory) DeleteEvents(ids []uuid.UUID) { } func NewAggregatingMemoryStore() *AggregatingMemory { - return &AggregatingMemory{WindowStart: time.Now(), Memory: Memory{events: make(map[uuid.UUID]*types.Event)}} + return &AggregatingMemory{WindowStart: time.Now(), Memory: Memory{events: make(map[uuid.UUID]*types.Event)}, rnd: v2.NewPCG(rand.Uint64(), rand.Uint64())} } func (am *AggregatingMemory) ResetAggregationWindow() types.FlowEventAggregator { am.mux.Lock() defer am.mux.Unlock() - toret := AggregatingMemory{WindowStart: am.WindowStart, WindowEnd: time.Now(), Memory: Memory{events: am.events}} + now := time.Now() + toret := AggregatingMemory{WindowStart: am.WindowStart, WindowEnd: now, Memory: Memory{events: am.events}} am.events = make(map[uuid.UUID]*types.Event) - am.WindowStart = time.Now() + am.WindowStart = now return &toret } @@ -81,7 +85,7 @@ type aggregationKey struct { direction int protocol uint8 icmpType uint8 - unique int64 // used to prevent aggregation on non icmp/udp/tcp events + unique uint64 // used to prevent aggregation on non icmp/udp/tcp events } func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { @@ -111,7 +115,7 @@ func (am *AggregatingMemory) GetAggregatedEvents() []*types.Event { event.WindowEnd = am.WindowEnd if event.Protocol != types.ICMP && event.Protocol != types.ICMPv6 && event.Protocol != types.UDP && event.Protocol != types.TCP { - lookupKey.unique = time.Now().UnixNano() // to make the lookup key unique so we don't aggregate on it + lookupKey.unique = am.rnd.Uint64() // to make the lookup key unique so we don't aggregate on it } aggregated[lookupKey] = event diff --git a/flow/proto/generate.sh b/flow/proto/generate.sh index fe447fd7acc..6bbf78e61ae 100755 --- a/flow/proto/generate.sh +++ b/flow/proto/generate.sh @@ -10,7 +10,6 @@ fi old_pwd=$(pwd) script_path=$(dirname $(realpath "$0")) -echo "$script_path" cd "$script_path" go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26 go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1 From 05308fb7dc4027d3fdca22b122717224d60e0418 Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Mon, 22 Jun 2026 19:18:15 +0200 Subject: [PATCH 30/30] small fix in a test Signed-off-by: Dmitri Dolguikh --- client/internal/netflow/store/event_aggregation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/internal/netflow/store/event_aggregation_test.go b/client/internal/netflow/store/event_aggregation_test.go index dbadef485aa..b9e95028f12 100644 --- a/client/internal/netflow/store/event_aggregation_test.go +++ b/client/internal/netflow/store/event_aggregation_test.go @@ -154,7 +154,7 @@ func TestFlowAggregationOfUnknownProtocols(t *testing.T) { }} for _, tt := range tests { - t.Run(tt.description+" "+string(types.ProtocolUnknown), func(t *testing.T) { + t.Run(tt.description+" "+types.ProtocolUnknown.String(), func(t *testing.T) { store := NewAggregatingMemoryStore() store.WindowEnd = time.Now().Add(5 * time.Second)