diff --git a/packages/api/go.mod b/packages/api/go.mod index dbb7cbe3c8..1029f2035f 100644 --- a/packages/api/go.mod +++ b/packages/api/go.mod @@ -16,6 +16,7 @@ tool ( ) require ( + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/bsm/redislock v0.9.4 github.com/caarlos0/env/v11 v11.3.1 github.com/e2b-dev/infra/packages/auth v0.0.0 diff --git a/packages/api/go.sum b/packages/api/go.sum index e01f66740d..6f0f7441bd 100644 --- a/packages/api/go.sum +++ b/packages/api/go.sum @@ -82,6 +82,8 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7D github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ= github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk= github.com/aws/aws-sdk-go-v2 v1.41.6 h1:1AX0AthnBQzMx1vbmir3Y4WsnJgiydmnJjiLu+LvXOg= diff --git a/packages/api/internal/api/api.gen.go b/packages/api/internal/api/api.gen.go index af4998a59c..176bcd2983 100644 --- a/packages/api/internal/api/api.gen.go +++ b/packages/api/internal/api/api.gen.go @@ -899,6 +899,21 @@ type SandboxNetworkConfig struct { // MaskRequestHost Specify host mask which will be used for all sandbox requests MaskRequestHost *string `json:"maskRequestHost,omitempty"` + + // Rules Per-domain transform rules applied to matching egress HTTP/HTTPS requests. Keys are domains (e.g. "api.example.com", "example.com"). A domain listed here is not automatically allowed - use allowOut to permit the traffic. + Rules *map[string][]SandboxNetworkRule `json:"rules,omitempty"` +} + +// SandboxNetworkRule Transform rule applied to egress requests matching a domain pattern. +type SandboxNetworkRule struct { + // Transform Transformations applied to matching egress requests before forwarding. + Transform *SandboxNetworkTransform `json:"transform,omitempty"` +} + +// SandboxNetworkTransform Transformations applied to matching egress requests before forwarding. +type SandboxNetworkTransform struct { + // Headers HTTP headers to inject or override in matching requests. An existing header with the same name is replaced. Values are plain strings; secret resolution happens client-side before sending to the API. + Headers *map[string]string `json:"headers,omitempty"` } // SandboxOnTimeout Action taken when the sandbox times out. @@ -1452,6 +1467,9 @@ type PutSandboxesSandboxIDNetworkJSONBody struct { // DenyOut List of denied CIDR blocks or IP addresses for egress traffic. Domain names are not supported for deny rules. DenyOut *[]string `json:"denyOut,omitempty"` + + // Rules Per-domain transform rules. Replaces all existing rules when provided. + Rules *map[string][]SandboxNetworkRule `json:"rules,omitempty"` } // PostSandboxesSandboxIDRefreshesJSONBody defines parameters for PostSandboxesSandboxIDRefreshes. @@ -12264,168 +12282,173 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/packages/api/internal/handlers/sandbox_create.go b/packages/api/internal/handlers/sandbox_create.go index a987f43296..88d5aa0d2f 100644 --- a/packages/api/internal/handlers/sandbox_create.go +++ b/packages/api/internal/handlers/sandbox_create.go @@ -11,12 +11,13 @@ import ( "strings" "time" + "github.com/asaskevich/govalidator" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/launchdarkly/go-sdk-common/v3/ldcontext" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" - "go.uber.org/zap" + "golang.org/x/net/http/httpguts" "golang.org/x/net/idna" "github.com/e2b-dev/infra/packages/api/internal/api" @@ -32,7 +33,6 @@ import ( "github.com/e2b-dev/infra/packages/shared/pkg/ginutils" "github.com/e2b-dev/infra/packages/shared/pkg/grpc/orchestrator" "github.com/e2b-dev/infra/packages/shared/pkg/id" - "github.com/e2b-dev/infra/packages/shared/pkg/logger" sbxlogger "github.com/e2b-dev/infra/packages/shared/pkg/logger/sandbox" "github.com/e2b-dev/infra/packages/shared/pkg/middleware/otel/metrics" sandbox_network "github.com/e2b-dev/infra/packages/shared/pkg/sandbox-network" @@ -47,6 +47,13 @@ const ( // Network validation error messages ErrMsgDomainsRequireBlockAll = "When specifying allowed domains in allow out, you must include 'ALL_TRAFFIC' in deny out to block all other traffic." + + maxNetworkRuleDomains = 10 + maxNetworkRuleTransformsPerDomain = 1 + maxNetworkRuleDomainLen = 128 + maxNetworkRuleHeaderNameLen = 64 + maxNetworkRuleHeaderValueLen = 2048 + maxNetworkRuleHeadersPerRule = 20 ) func (a *APIStore) PostSandboxes(c *gin.Context) { @@ -174,7 +181,7 @@ func (a *APIStore) PostSandboxes(c *gin.Context) { var network *types.SandboxNetworkConfig if n := body.Network; n != nil { - if err := validateNetworkConfig(n); err != nil { + if err := validateNetworkConfig(ctx, a.featureFlags, teamInfo.Team.ID, sharedUtils.DerefOrDefault(build.EnvdVersion, ""), n); err != nil { telemetry.ReportError(ctx, "invalid network config", err.Err, telemetry.WithSandboxID(sandboxID)) a.sendAPIStoreError(c, err.Code, err.ClientMsg) @@ -189,6 +196,7 @@ func (a *APIStore) PostSandboxes(c *gin.Context) { Egress: &types.SandboxNetworkEgressConfig{ AllowedAddresses: sharedUtils.DerefOrDefault(n.AllowOut, nil), DeniedAddresses: sharedUtils.DerefOrDefault(n.DenyOut, nil), + Rules: apiRulesToDBRules(n.Rules), }, } @@ -265,6 +273,19 @@ func (a *APIStore) PostSandboxes(c *gin.Context) { return } + if n := body.Network; n != nil && n.Rules != nil && len(*n.Rules) > 0 { + domains := make([]string, 0, len(*n.Rules)) + for domain := range *n.Rules { + domains = append(domains, domain) + } + + a.posthog.CreateAnalyticsTeamEvent(ctx, teamInfo.Team.ID.String(), "sandbox with network transform rules created", + a.posthog.GetPackageToPosthogProperties(&c.Request.Header). + Set("sandbox_id", sandboxID). + Set("domains", domains), + ) + } + c.JSON(http.StatusCreated, &sbx) } @@ -324,10 +345,35 @@ func (im InvalidVolumeMountsError) Error() string { var errVolumesNotSupported = errors.New("volumes are not supported") +var errNetworkRulesNotSupported = errors.New("network transform rules are not supported") + var errNoEnvdVersion = errors.New("no envd version provided") +const minEnvdVersionForNetworkRules = "0.5.13" + const minEnvdVersionForVolumes = "0.5.14" +// checkEnvdVersionRequirement returns errNoEnvdVersion when buildVersion is empty, a parse +// error when the version string is invalid, or a wrapped featureErr when the build does not +// meet requiredMinVersion. The caller decides how to convert the returned error into an API +// response so each call-site can produce its own status code / message. +func checkEnvdVersionRequirement(buildVersion, requiredMinVersion string, featureErr error) error { + if buildVersion == "" { + return errNoEnvdVersion + } + + ok, err := sharedUtils.IsGTEVersion(buildVersion, requiredMinVersion) + if err != nil { + return fmt.Errorf("invalid envd version %q: %w", buildVersion, err) + } + + if !ok { + return fmt.Errorf("%w; template must be rebuilt. Template envd version is %s, must be at least %s", featureErr, buildVersion, requiredMinVersion) + } + + return nil +} + func convertAPIVolumesToOrchestratorVolumes(ctx context.Context, sqlClient *sqlcdb.Client, featureFlags featureFlagsClient, teamID uuid.UUID, volumeMounts []api.SandboxVolumeMount, env *queries.EnvBuild) ([]*orchestrator.SandboxVolumeMount, error) { // are any volumes configured? if len(volumeMounts) == 0 { @@ -340,16 +386,9 @@ func convertAPIVolumesToOrchestratorVolumes(ctx context.Context, sqlClient *sqlc } // does your envd version support volumes? - if envdVersion := sharedUtils.DerefOrDefault(env.EnvdVersion, ""); envdVersion == "" { - logger.L().Warn(ctx, "envd version is unset") - - return nil, errNoEnvdVersion - } else if ok, err := sharedUtils.IsGTEVersion(envdVersion, minEnvdVersionForVolumes); err != nil { - logger.L().Warn(ctx, "failed to check envd version", zap.Error(err), zap.String("envd_version", envdVersion)) - - return nil, fmt.Errorf("invalid envd version %q: %w", envdVersion, err) - } else if !ok { - return nil, fmt.Errorf("%w; template must be rebuilt. Template envd version is %s, must be at least %s to support volumes", errVolumesNotSupported, envdVersion, minEnvdVersionForVolumes) + envdVersion := sharedUtils.DerefOrDefault(env.EnvdVersion, "") + if err := checkEnvdVersionRequirement(envdVersion, minEnvdVersionForVolumes, errVolumesNotSupported); err != nil { + return nil, err } // get volumes from the database @@ -514,7 +553,33 @@ func splitHostPortOptional(hostport string) (host string, port string, err error return host, port, nil } -func validateNetworkConfig(network *api.SandboxNetworkConfig) *api.APIError { +func apiRulesToDBRules(apiRules *map[string][]api.SandboxNetworkRule) map[string][]types.SandboxNetworkRule { + if apiRules == nil { + return nil + } + + dbRules := make(map[string][]types.SandboxNetworkRule, len(*apiRules)) + for domain, rules := range *apiRules { + dbDomainRules := make([]types.SandboxNetworkRule, 0, len(rules)) + for _, r := range rules { + dbRule := types.SandboxNetworkRule{} + + if r.Transform != nil { + dbRule.Transform = &types.SandboxNetworkTransform{ + Headers: sharedUtils.DerefOrDefault(r.Transform.Headers, nil), + } + } + + dbDomainRules = append(dbDomainRules, dbRule) + } + + dbRules[domain] = dbDomainRules + } + + return dbRules +} + +func validateNetworkConfig(ctx context.Context, featureFlags featureFlagsClient, teamID uuid.UUID, envdVersion string, network *api.SandboxNetworkConfig) *api.APIError { if network == nil { return nil } @@ -550,7 +615,11 @@ func validateNetworkConfig(network *api.SandboxNetworkConfig) *api.APIError { denyOut := sharedUtils.DerefOrDefault(network.DenyOut, nil) allowOut := sharedUtils.DerefOrDefault(network.AllowOut, nil) - return validateEgressRules(allowOut, denyOut) + if err := validateEgressRules(allowOut, denyOut); err != nil { + return err + } + + return validateNetworkRules(ctx, featureFlags, teamID, envdVersion, network.Rules) } // validateEgressRules validates egress allow/deny rules: @@ -593,3 +662,134 @@ func validateEgressRules(allowOut, denyOut []string) *api.APIError { return nil } + +func validateNetworkRules(ctx context.Context, featureFlags featureFlagsClient, teamID uuid.UUID, envdVersion string, rules *map[string][]api.SandboxNetworkRule) *api.APIError { + if rules == nil { + return nil + } + + if !featureFlags.BoolFlag(ctx, featureflags.NetworkTransformRulesFlag, featureflags.TeamContext(teamID.String())) { + return &api.APIError{ + Code: http.StatusBadRequest, + Err: fmt.Errorf("team %s is not allowed to use network transform rules", teamID), + ClientMsg: "Network transform rules are not available for your team.", + } + } + + if err := checkEnvdVersionRequirement(envdVersion, minEnvdVersionForNetworkRules, errNetworkRulesNotSupported); err != nil { + if errors.Is(err, errNetworkRulesNotSupported) { + return &api.APIError{ + Code: http.StatusBadRequest, + Err: err, + ClientMsg: err.Error(), + } + } + + return &api.APIError{ + Code: http.StatusInternalServerError, + Err: err, + ClientMsg: "internal error while validating network rules", + } + } + + if len(*rules) > maxNetworkRuleDomains { + return &api.APIError{ + Code: http.StatusBadRequest, + Err: fmt.Errorf("too many rule domains: %d (max %d)", len(*rules), maxNetworkRuleDomains), + ClientMsg: fmt.Sprintf("Network rules can have at most %d domains.", maxNetworkRuleDomains), + } + } + + for domain, domainRules := range *rules { + if len(domain) == 0 { + return &api.APIError{ + Code: http.StatusBadRequest, + Err: errors.New("rule domain must not be empty"), + ClientMsg: "Rule domain must not be empty.", + } + } + + if len(domain) > maxNetworkRuleDomainLen { + return &api.APIError{ + Code: http.StatusBadRequest, + Err: fmt.Errorf("rule domain %q exceeds max length %d", domain, maxNetworkRuleDomainLen), + ClientMsg: fmt.Sprintf("Rule domain %q exceeds maximum length of %d characters.", domain, maxNetworkRuleDomainLen), + } + } + + if !govalidator.IsDNSName(domain) { + return &api.APIError{ + Code: http.StatusBadRequest, + Err: fmt.Errorf("rule domain %q is not a valid domain", domain), + ClientMsg: fmt.Sprintf("Rule domain %q is not a valid domain name.", domain), + } + } + + if len(domainRules) > maxNetworkRuleTransformsPerDomain { + return &api.APIError{ + Code: http.StatusBadRequest, + Err: fmt.Errorf("domain %q has %d transforms (max %d)", domain, len(domainRules), maxNetworkRuleTransformsPerDomain), + ClientMsg: fmt.Sprintf("Domain %q can have at most %d transform rule.", domain, maxNetworkRuleTransformsPerDomain), + } + } + + for _, rule := range domainRules { + if rule.Transform == nil { + continue + } + + headers := sharedUtils.DerefOrDefault(rule.Transform.Headers, nil) + if len(headers) > maxNetworkRuleHeadersPerRule { + return &api.APIError{ + Code: http.StatusBadRequest, + Err: fmt.Errorf("domain %q has %d headers (max %d)", domain, len(headers), maxNetworkRuleHeadersPerRule), + ClientMsg: fmt.Sprintf("Domain %q can have at most %d headers per rule.", domain, maxNetworkRuleHeadersPerRule), + } + } + + for name, value := range headers { + if len(name) == 0 { + return &api.APIError{ + Code: http.StatusBadRequest, + Err: fmt.Errorf("header name in rule for domain %q must not be empty", domain), + ClientMsg: fmt.Sprintf("Header name in rule for domain %q must not be empty.", domain), + } + } + + if !httpguts.ValidHeaderFieldName(name) { + return &api.APIError{ + Code: http.StatusBadRequest, + Err: fmt.Errorf("header name %q in rule for domain %q contains invalid characters", name, domain), + ClientMsg: fmt.Sprintf("Header name %q in rule for domain %q must contain only valid HTTP token characters.", name, domain), + } + } + + if len(name) > maxNetworkRuleHeaderNameLen { + return &api.APIError{ + Code: http.StatusBadRequest, + Err: fmt.Errorf("header name %q in rule for domain %q exceeds max length %d", name, domain, maxNetworkRuleHeaderNameLen), + ClientMsg: fmt.Sprintf("Header name %q in rule for domain %q exceeds maximum length of %d characters.", name, domain, maxNetworkRuleHeaderNameLen), + } + } + + if !httpguts.ValidHeaderFieldValue(value) { + return &api.APIError{ + Code: http.StatusBadRequest, + Err: fmt.Errorf("value for header %q in rule for domain %q contains invalid characters", name, domain), + ClientMsg: fmt.Sprintf("Value for header %q in rule for domain %q contains invalid characters.", name, domain), + } + } + + if len(value) > maxNetworkRuleHeaderValueLen { + return &api.APIError{ + Code: http.StatusBadRequest, + Err: fmt.Errorf("value for header %q in rule for domain %q exceeds max length %d", name, domain, maxNetworkRuleHeaderValueLen), + ClientMsg: fmt.Sprintf("Value for header %q in rule for domain %q exceeds maximum length of %d characters.", name, domain, maxNetworkRuleHeaderValueLen), + } + } + } + } + } + + return nil +} diff --git a/packages/api/internal/handlers/sandbox_create_test.go b/packages/api/internal/handlers/sandbox_create_test.go index 7bc88e64dd..5bba27d32b 100644 --- a/packages/api/internal/handlers/sandbox_create_test.go +++ b/packages/api/internal/handlers/sandbox_create_test.go @@ -7,6 +7,7 @@ import ( "fmt" "net/http" "net/http/httptest" + "strings" "testing" "github.com/gin-gonic/gin" @@ -278,7 +279,8 @@ func TestValidateNetworkConfig(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() - err := validateNetworkConfig(tt.network) + mockFF := handlersmocks.NewMockFeatureFlagsClient(t) + err := validateNetworkConfig(context.Background(), mockFF, uuid.Nil, "", tt.network) if tt.wantErr { if err == nil { @@ -777,6 +779,281 @@ func createTestTemplate(ctx context.Context, t *testing.T, db *testutils.Databas return templateID } +func ffEnabled(t *testing.T) *handlersmocks.MockFeatureFlagsClient { + t.Helper() + ff := handlersmocks.NewMockFeatureFlagsClient(t) + ff.EXPECT().BoolFlag(mock.Anything, mock.Anything, mock.Anything).Return(true) + + return ff +} + +func ffDisabled(t *testing.T) *handlersmocks.MockFeatureFlagsClient { + t.Helper() + ff := handlersmocks.NewMockFeatureFlagsClient(t) + ff.EXPECT().BoolFlag(mock.Anything, mock.Anything, mock.Anything).Return(false) + + return ff +} + +func ffUnused(t *testing.T) *handlersmocks.MockFeatureFlagsClient { + t.Helper() + + return handlersmocks.NewMockFeatureFlagsClient(t) // no expectations — must not be called +} + +func rulesMap(entries map[string][]api.SandboxNetworkRule) *map[string][]api.SandboxNetworkRule { + return &entries +} + +func simpleRule(headers map[string]string) api.SandboxNetworkRule { + h := headers + + return api.SandboxNetworkRule{ + Transform: &api.SandboxNetworkTransform{Headers: &h}, + } +} + +func TestValidateNetworkRules(t *testing.T) { + t.Parallel() + + teamID := uuid.New() + + tests := []struct { + name string + envdVersion string + rules *map[string][]api.SandboxNetworkRule + setupFF func(t *testing.T) *handlersmocks.MockFeatureFlagsClient + wantCode int + wantMsg string // substring of ClientMsg; empty means expect no error + }{ + // ── nil / empty ────────────────────────────────────────────────────────── + { + name: "nil rules are valid", + rules: nil, + setupFF: ffUnused, + }, + { + name: "empty rules map is valid", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{}), + setupFF: ffEnabled, + }, + // ── feature flag ───────────────────────────────────────────────────────── + { + name: "feature flag disabled returns 400", + rules: rulesMap(map[string][]api.SandboxNetworkRule{"api.openai.com": {}}), + setupFF: ffDisabled, + wantCode: http.StatusBadRequest, + wantMsg: "not available for your team", + }, + // ── envd version ───────────────────────────────────────────────────────── + { + name: "missing envd version returns 500", + rules: rulesMap(map[string][]api.SandboxNetworkRule{"api.openai.com": {}}), + setupFF: ffEnabled, + wantCode: http.StatusInternalServerError, + wantMsg: "internal error while validating network rules", + }, + { + name: "envd version below minimum returns 400", + envdVersion: "0.5.12", + rules: rulesMap(map[string][]api.SandboxNetworkRule{"api.openai.com": {}}), + setupFF: ffEnabled, + wantCode: http.StatusBadRequest, + wantMsg: "template must be rebuilt", + }, + { + name: "envd version at minimum is valid", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{"api.openai.com": {}}), + setupFF: ffEnabled, + }, + // ── domain count ───────────────────────────────────────────────────────── + { + name: "exactly max domains is valid", + rules: func() *map[string][]api.SandboxNetworkRule { + m := make(map[string][]api.SandboxNetworkRule, maxNetworkRuleDomains) + for i := range maxNetworkRuleDomains { + m[fmt.Sprintf("domain%d.example.com", i)] = nil + } + + return &m + }(), + envdVersion: minEnvdVersionForNetworkRules, + setupFF: ffEnabled, + }, + { + name: "one over max domains returns 400", + rules: func() *map[string][]api.SandboxNetworkRule { + m := make(map[string][]api.SandboxNetworkRule, maxNetworkRuleDomains+1) + for i := range maxNetworkRuleDomains + 1 { + m[fmt.Sprintf("domain%d.example.com", i)] = nil + } + + return &m + }(), + envdVersion: minEnvdVersionForNetworkRules, + setupFF: ffEnabled, + wantCode: http.StatusBadRequest, + wantMsg: fmt.Sprintf("at most %d domains", maxNetworkRuleDomains), + }, + // ── domain key validation ───────────────────────────────────────────────── + { + name: "empty domain key returns 400", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{"": {}}), + setupFF: ffEnabled, + wantCode: http.StatusBadRequest, + wantMsg: "must not be empty", + }, + { + name: "domain exceeding max length returns 400", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{strings.Repeat("a", maxNetworkRuleDomainLen+1): {}}), + setupFF: ffEnabled, + wantCode: http.StatusBadRequest, + wantMsg: "maximum length", + }, + { + name: "invalid domain returns 400", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{"not a valid domain!": {}}), + setupFF: ffEnabled, + wantCode: http.StatusBadRequest, + wantMsg: "not a valid domain name", + }, + { + name: "valid plain domain is accepted", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{"api.openai.com": {}}), + setupFF: ffEnabled, + }, + { + name: "wildcard domain is rejected", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{"*.openai.com": {}}), + setupFF: ffEnabled, + wantCode: http.StatusBadRequest, + wantMsg: "not a valid domain name", + }, + { + name: "bare wildcard is rejected", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{"*.": {}}), + setupFF: ffEnabled, + wantCode: http.StatusBadRequest, + wantMsg: "not a valid domain name", + }, + // ── transform count ─────────────────────────────────────────────────────── + { + name: "one transform per domain is valid", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{ + "api.openai.com": {simpleRule(map[string]string{"Authorization": "Bearer token"})}, + }), + setupFF: ffEnabled, + }, + { + name: "two transforms for one domain returns 400", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{ + "api.openai.com": { + simpleRule(map[string]string{"Authorization": "Bearer token"}), + simpleRule(map[string]string{"X-Custom": "value"}), + }, + }), + setupFF: ffEnabled, + wantCode: http.StatusBadRequest, + wantMsg: fmt.Sprintf("at most %d transform rule", maxNetworkRuleTransformsPerDomain), + }, + // ── nil transform (no headers to check) ─────────────────────────────────── + { + name: "nil transform in rule is valid", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{ + "api.openai.com": {{Transform: nil}}, + }), + setupFF: ffEnabled, + }, + // ── header name ─────────────────────────────────────────────────────────── + { + name: "empty header name returns 400", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{ + "api.openai.com": {simpleRule(map[string]string{"": "value"})}, + }), + setupFF: ffEnabled, + wantCode: http.StatusBadRequest, + wantMsg: "must not be empty", + }, + { + name: "header name at max length is valid", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{ + "api.openai.com": {simpleRule(map[string]string{ + strings.Repeat("X", maxNetworkRuleHeaderNameLen): "value", + })}, + }), + setupFF: ffEnabled, + }, + { + name: "header name exceeding max length returns 400", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{ + "api.openai.com": {simpleRule(map[string]string{ + strings.Repeat("X", maxNetworkRuleHeaderNameLen+1): "value", + })}, + }), + setupFF: ffEnabled, + wantCode: http.StatusBadRequest, + wantMsg: "maximum length", + }, + // ── header value ────────────────────────────────────────────────────────── + { + name: "header value at max length is valid", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{ + "api.openai.com": {simpleRule(map[string]string{ + "Authorization": strings.Repeat("x", maxNetworkRuleHeaderValueLen), + })}, + }), + setupFF: ffEnabled, + }, + { + name: "header value exceeding max length returns 400", + envdVersion: minEnvdVersionForNetworkRules, + rules: rulesMap(map[string][]api.SandboxNetworkRule{ + "api.openai.com": {simpleRule(map[string]string{ + "Authorization": strings.Repeat("x", maxNetworkRuleHeaderValueLen+1), + })}, + }), + setupFF: ffEnabled, + wantCode: http.StatusBadRequest, + wantMsg: "maximum length", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + ff := tt.setupFF(t) + apiErr := validateNetworkRules(context.Background(), ff, teamID, tt.envdVersion, tt.rules) + + if tt.wantMsg == "" { + assert.Nil(t, apiErr) + + return + } + + if assert.NotNil(t, apiErr) { + assert.Equal(t, tt.wantCode, apiErr.Code) + assert.Contains(t, apiErr.ClientMsg, tt.wantMsg) + } + }) + } +} + func createTestTemplateAliasWithName(ctx context.Context, t *testing.T, db *testutils.Database, templateID, aliasName string, namespace *string) { t.Helper() diff --git a/packages/api/internal/handlers/sandbox_get.go b/packages/api/internal/handlers/sandbox_get.go index db1af5f23a..0509d8025c 100644 --- a/packages/api/internal/handlers/sandbox_get.go +++ b/packages/api/internal/handlers/sandbox_get.go @@ -3,6 +3,7 @@ package handlers import ( "errors" "fmt" + "maps" "net/http" "github.com/gin-gonic/gin" @@ -46,9 +47,33 @@ func dbNetworkConfigToAPI(network *dbtypes.SandboxNetworkConfig) *api.SandboxNet if egress.AllowedAddresses != nil { result.AllowOut = &egress.AllowedAddresses } + if egress.DeniedAddresses != nil { result.DenyOut = &egress.DeniedAddresses } + + if egress.Rules != nil { + apiRules := make(map[string][]api.SandboxNetworkRule, len(egress.Rules)) + for domain, dbRules := range egress.Rules { + apiDomainRules := make([]api.SandboxNetworkRule, 0, len(dbRules)) + for _, r := range dbRules { + apiRule := api.SandboxNetworkRule{} + if r.Transform != nil { + var h *map[string]string + if r.Transform.Headers != nil { + clone := maps.Clone(r.Transform.Headers) + h = &clone + } + apiRule.Transform = &api.SandboxNetworkTransform{ + Headers: h, + } + } + apiDomainRules = append(apiDomainRules, apiRule) + } + apiRules[domain] = apiDomainRules + } + result.Rules = &apiRules + } } return result diff --git a/packages/api/internal/handlers/sandbox_network_update.go b/packages/api/internal/handlers/sandbox_network_update.go index 0b68d983a2..f5d23d8e2f 100644 --- a/packages/api/internal/handlers/sandbox_network_update.go +++ b/packages/api/internal/handlers/sandbox_network_update.go @@ -1,22 +1,21 @@ package handlers import ( + "errors" "fmt" "net/http" "github.com/gin-gonic/gin" "github.com/e2b-dev/infra/packages/api/internal/api" + "github.com/e2b-dev/infra/packages/api/internal/sandbox" "github.com/e2b-dev/infra/packages/api/internal/utils" "github.com/e2b-dev/infra/packages/auth/pkg/auth" "github.com/e2b-dev/infra/packages/shared/pkg/ginutils" "github.com/e2b-dev/infra/packages/shared/pkg/telemetry" ) -func (a *APIStore) PutSandboxesSandboxIDNetwork( - c *gin.Context, - sandboxID string, -) { +func (a *APIStore) PutSandboxesSandboxIDNetwork(c *gin.Context, sandboxID string) { ctx := c.Request.Context() var err error @@ -53,12 +52,45 @@ func (a *APIStore) PutSandboxesSandboxIDNetwork( return } - if apiErr := a.orchestrator.UpdateSandboxNetworkConfig(ctx, team.ID, sandboxID, allowedEntries, deniedEntries, body.AllowInternetAccess); apiErr != nil { + sbxInfo, err := a.orchestrator.GetSandbox(ctx, team.ID, sandboxID) + if err != nil { + if errors.Is(err, sandbox.ErrNotFound) { + a.sendAPIStoreError(c, http.StatusNotFound, utils.SandboxNotFoundMsg(sandboxID)) + } else { + telemetry.ReportError(ctx, "error getting sandbox for network update", err) + a.sendAPIStoreError(c, http.StatusInternalServerError, "Failed to get sandbox") + } + + return + } + + if apiErr := validateNetworkRules(ctx, a.featureFlags, team.ID, sbxInfo.EnvdVersion, body.Rules); apiErr != nil { + a.sendAPIStoreError(c, apiErr.Code, apiErr.ClientMsg) + + return + } + + rules := apiRulesToDBRules(body.Rules) + + if apiErr := a.orchestrator.UpdateSandboxNetworkConfig(ctx, team.ID, sandboxID, allowedEntries, deniedEntries, rules, body.AllowInternetAccess); apiErr != nil { telemetry.ReportErrorByCode(ctx, apiErr.Code, "error updating sandbox network config", apiErr.Err) a.sendAPIStoreError(c, apiErr.Code, apiErr.ClientMsg) return } + if len(rules) > 0 { + domains := make([]string, 0, len(rules)) + for domain := range rules { + domains = append(domains, domain) + } + + a.posthog.CreateAnalyticsTeamEvent(ctx, team.ID.String(), "sandbox with network transform rules updated", + a.posthog.GetPackageToPosthogProperties(&c.Request.Header). + Set("sandbox_id", sandboxID). + Set("domains", domains), + ) + } + c.Status(http.StatusNoContent) } diff --git a/packages/api/internal/orchestrator/create_instance.go b/packages/api/internal/orchestrator/create_instance.go index 8eedc0581e..46855aa912 100644 --- a/packages/api/internal/orchestrator/create_instance.go +++ b/packages/api/internal/orchestrator/create_instance.go @@ -55,17 +55,36 @@ type SandboxMetadata struct { // allow/deny entry lists. It splits allowed entries into CIDRs and domains, // and adds the default nameserver when domains are present so the sandbox can // resolve them. -func buildEgressConfig(allowedEntries, deniedEntries []string) *orchestrator.SandboxNetworkEgressConfig { +func buildEgressConfig(allowedEntries, deniedEntries []string, rules map[string][]types.SandboxNetworkRule) *orchestrator.SandboxNetworkEgressConfig { allowedAddresses, allowedDomains := sandbox_network.ParseAddressesAndDomains(allowedEntries) if len(allowedDomains) > 0 { allowedAddresses = append(allowedAddresses, sandbox_network.DefaultNameserver) } + var orchRules map[string]*orchestrator.SandboxNetworkDomainRules + if rules != nil { + orchRules = make(map[string]*orchestrator.SandboxNetworkDomainRules, len(rules)) + for domain, domainRules := range rules { + orchRuleList := make([]*orchestrator.SandboxNetworkRule, 0, len(domainRules)) + for _, r := range domainRules { + orchRule := &orchestrator.SandboxNetworkRule{} + if r.Transform != nil { + orchRule.Transform = &orchestrator.SandboxNetworkTransform{ + Headers: r.Transform.Headers, + } + } + orchRuleList = append(orchRuleList, orchRule) + } + orchRules[domain] = &orchestrator.SandboxNetworkDomainRules{Rules: orchRuleList} + } + } + return &orchestrator.SandboxNetworkEgressConfig{ AllowedCidrs: sandbox_network.AddressStringsToCIDRs(allowedAddresses), DeniedCidrs: sandbox_network.AddressStringsToCIDRs(deniedEntries), AllowedDomains: allowedDomains, + Rules: orchRules, } } @@ -79,7 +98,7 @@ func buildNetworkConfig(network *types.SandboxNetworkConfig, allowInternetAccess } if network != nil && network.Egress != nil { - orchNetwork.Egress = buildEgressConfig(network.Egress.AllowedAddresses, network.Egress.DeniedAddresses) + orchNetwork.Egress = buildEgressConfig(network.Egress.AllowedAddresses, network.Egress.DeniedAddresses, network.Egress.Rules) } if network != nil && network.Ingress != nil { diff --git a/packages/api/internal/orchestrator/update_network.go b/packages/api/internal/orchestrator/update_network.go index f54ca2661e..cfceb45d30 100644 --- a/packages/api/internal/orchestrator/update_network.go +++ b/packages/api/internal/orchestrator/update_network.go @@ -26,12 +26,14 @@ func (o *Orchestrator) UpdateSandboxNetworkConfig( sandboxID string, allowedEntries []string, deniedEntries []string, + rules map[string][]types.SandboxNetworkRule, allowInternetAccess *bool, ) *api.APIError { network := &types.SandboxNetworkConfig{ Egress: &types.SandboxNetworkEgressConfig{ AllowedAddresses: allowedEntries, DeniedAddresses: deniedEntries, + Rules: rules, }, } orchNetwork := buildNetworkConfig(network, allowInternetAccess, nil) @@ -49,6 +51,7 @@ func (o *Orchestrator) UpdateSandboxNetworkConfig( sbx.Network.Egress = &types.SandboxNetworkEgressConfig{ AllowedAddresses: allowedEntries, DeniedAddresses: deniedEntries, + Rules: rules, } if allowInternetAccess != nil { diff --git a/packages/db/pkg/types/types.go b/packages/db/pkg/types/types.go index a1444001a7..996dd1523f 100644 --- a/packages/db/pkg/types/types.go +++ b/packages/db/pkg/types/types.go @@ -63,9 +63,18 @@ func (r BuildReason) Value() (driver.Value, error) { const PausedSandboxConfigVersion = "v1" +type SandboxNetworkTransform struct { + Headers map[string]string `json:"headers,omitempty"` +} + +type SandboxNetworkRule struct { + Transform *SandboxNetworkTransform `json:"transform,omitempty"` +} + type SandboxNetworkEgressConfig struct { - AllowedAddresses []string `json:"allowedAddresses,omitempty"` - DeniedAddresses []string `json:"deniedAddresses,omitempty"` + AllowedAddresses []string `json:"allowedAddresses,omitempty"` + DeniedAddresses []string `json:"deniedAddresses,omitempty"` + Rules map[string][]SandboxNetworkRule `json:"rules,omitempty"` } const AllowPublicAccessDefault = true diff --git a/packages/orchestrator/main.go b/packages/orchestrator/main.go index d4b8347dae..b1b415d520 100644 --- a/packages/orchestrator/main.go +++ b/packages/orchestrator/main.go @@ -7,7 +7,7 @@ import ( "github.com/e2b-dev/infra/packages/orchestrator/pkg/tcpfirewall" ) -const version = "0.1.0" +const version = "0.2.0" var commitSHA string diff --git a/packages/orchestrator/orchestrator.proto b/packages/orchestrator/orchestrator.proto index 37a75e3914..abb18c3ee2 100644 --- a/packages/orchestrator/orchestrator.proto +++ b/packages/orchestrator/orchestrator.proto @@ -72,11 +72,23 @@ message SandboxNetworkConfig { optional SandboxNetworkIngressConfig ingress = 2; } +message SandboxNetworkTransform { + map headers = 1; +} + +message SandboxNetworkRule { + optional SandboxNetworkTransform transform = 1; +} + +message SandboxNetworkDomainRules { + repeated SandboxNetworkRule rules = 1; +} + message SandboxNetworkEgressConfig { repeated string allowed_cidrs = 1; repeated string denied_cidrs = 2; - repeated string allowed_domains = 3; + map rules = 4; } message SandboxNetworkIngressConfig { diff --git a/packages/shared/pkg/featureflags/flags.go b/packages/shared/pkg/featureflags/flags.go index 83a4a0c11c..200e977db8 100644 --- a/packages/shared/pkg/featureflags/flags.go +++ b/packages/shared/pkg/featureflags/flags.go @@ -119,6 +119,8 @@ var ( ExecutionMetricsOnWebhooksFlag = NewBoolFlag("execution-metrics-on-webhooks", false) // TODO: Remove NLT 20250315 SandboxLabelBasedSchedulingFlag = NewBoolFlag("sandbox-label-based-scheduling", false) OptimisticResourceAccountingFlag = NewBoolFlag("sandbox-placement-optimistic-resource-accounting", false) + + NetworkTransformRulesFlag = NewBoolFlag("network-transform-rules", env.IsDevelopment()) ) type IntFlag struct { diff --git a/packages/shared/pkg/grpc/orchestrator/orchestrator.pb.go b/packages/shared/pkg/grpc/orchestrator/orchestrator.pb.go index bd60a3ead8..45cfe61ed8 100644 --- a/packages/shared/pkg/grpc/orchestrator/orchestrator.pb.go +++ b/packages/shared/pkg/grpc/orchestrator/orchestrator.pb.go @@ -443,20 +443,162 @@ func (x *SandboxNetworkConfig) GetIngress() *SandboxNetworkIngressConfig { return nil } +type SandboxNetworkTransform struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Headers map[string]string `protobuf:"bytes,1,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *SandboxNetworkTransform) Reset() { + *x = SandboxNetworkTransform{} + if protoimpl.UnsafeEnabled { + mi := &file_orchestrator_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SandboxNetworkTransform) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxNetworkTransform) ProtoMessage() {} + +func (x *SandboxNetworkTransform) ProtoReflect() protoreflect.Message { + mi := &file_orchestrator_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxNetworkTransform.ProtoReflect.Descriptor instead. +func (*SandboxNetworkTransform) Descriptor() ([]byte, []int) { + return file_orchestrator_proto_rawDescGZIP(), []int{4} +} + +func (x *SandboxNetworkTransform) GetHeaders() map[string]string { + if x != nil { + return x.Headers + } + return nil +} + +type SandboxNetworkRule struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Transform *SandboxNetworkTransform `protobuf:"bytes,1,opt,name=transform,proto3,oneof" json:"transform,omitempty"` +} + +func (x *SandboxNetworkRule) Reset() { + *x = SandboxNetworkRule{} + if protoimpl.UnsafeEnabled { + mi := &file_orchestrator_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SandboxNetworkRule) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxNetworkRule) ProtoMessage() {} + +func (x *SandboxNetworkRule) ProtoReflect() protoreflect.Message { + mi := &file_orchestrator_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxNetworkRule.ProtoReflect.Descriptor instead. +func (*SandboxNetworkRule) Descriptor() ([]byte, []int) { + return file_orchestrator_proto_rawDescGZIP(), []int{5} +} + +func (x *SandboxNetworkRule) GetTransform() *SandboxNetworkTransform { + if x != nil { + return x.Transform + } + return nil +} + +type SandboxNetworkDomainRules struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Rules []*SandboxNetworkRule `protobuf:"bytes,1,rep,name=rules,proto3" json:"rules,omitempty"` +} + +func (x *SandboxNetworkDomainRules) Reset() { + *x = SandboxNetworkDomainRules{} + if protoimpl.UnsafeEnabled { + mi := &file_orchestrator_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SandboxNetworkDomainRules) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxNetworkDomainRules) ProtoMessage() {} + +func (x *SandboxNetworkDomainRules) ProtoReflect() protoreflect.Message { + mi := &file_orchestrator_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SandboxNetworkDomainRules.ProtoReflect.Descriptor instead. +func (*SandboxNetworkDomainRules) Descriptor() ([]byte, []int) { + return file_orchestrator_proto_rawDescGZIP(), []int{6} +} + +func (x *SandboxNetworkDomainRules) GetRules() []*SandboxNetworkRule { + if x != nil { + return x.Rules + } + return nil +} + type SandboxNetworkEgressConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - AllowedCidrs []string `protobuf:"bytes,1,rep,name=allowed_cidrs,json=allowedCidrs,proto3" json:"allowed_cidrs,omitempty"` - DeniedCidrs []string `protobuf:"bytes,2,rep,name=denied_cidrs,json=deniedCidrs,proto3" json:"denied_cidrs,omitempty"` - AllowedDomains []string `protobuf:"bytes,3,rep,name=allowed_domains,json=allowedDomains,proto3" json:"allowed_domains,omitempty"` + AllowedCidrs []string `protobuf:"bytes,1,rep,name=allowed_cidrs,json=allowedCidrs,proto3" json:"allowed_cidrs,omitempty"` + DeniedCidrs []string `protobuf:"bytes,2,rep,name=denied_cidrs,json=deniedCidrs,proto3" json:"denied_cidrs,omitempty"` + AllowedDomains []string `protobuf:"bytes,3,rep,name=allowed_domains,json=allowedDomains,proto3" json:"allowed_domains,omitempty"` + Rules map[string]*SandboxNetworkDomainRules `protobuf:"bytes,4,rep,name=rules,proto3" json:"rules,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` } func (x *SandboxNetworkEgressConfig) Reset() { *x = SandboxNetworkEgressConfig{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_proto_msgTypes[4] + mi := &file_orchestrator_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -469,7 +611,7 @@ func (x *SandboxNetworkEgressConfig) String() string { func (*SandboxNetworkEgressConfig) ProtoMessage() {} func (x *SandboxNetworkEgressConfig) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_proto_msgTypes[4] + mi := &file_orchestrator_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -482,7 +624,7 @@ func (x *SandboxNetworkEgressConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxNetworkEgressConfig.ProtoReflect.Descriptor instead. func (*SandboxNetworkEgressConfig) Descriptor() ([]byte, []int) { - return file_orchestrator_proto_rawDescGZIP(), []int{4} + return file_orchestrator_proto_rawDescGZIP(), []int{7} } func (x *SandboxNetworkEgressConfig) GetAllowedCidrs() []string { @@ -506,6 +648,13 @@ func (x *SandboxNetworkEgressConfig) GetAllowedDomains() []string { return nil } +func (x *SandboxNetworkEgressConfig) GetRules() map[string]*SandboxNetworkDomainRules { + if x != nil { + return x.Rules + } + return nil +} + type SandboxNetworkIngressConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -518,7 +667,7 @@ type SandboxNetworkIngressConfig struct { func (x *SandboxNetworkIngressConfig) Reset() { *x = SandboxNetworkIngressConfig{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_proto_msgTypes[5] + mi := &file_orchestrator_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -531,7 +680,7 @@ func (x *SandboxNetworkIngressConfig) String() string { func (*SandboxNetworkIngressConfig) ProtoMessage() {} func (x *SandboxNetworkIngressConfig) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_proto_msgTypes[5] + mi := &file_orchestrator_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -544,7 +693,7 @@ func (x *SandboxNetworkIngressConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxNetworkIngressConfig.ProtoReflect.Descriptor instead. func (*SandboxNetworkIngressConfig) Descriptor() ([]byte, []int) { - return file_orchestrator_proto_rawDescGZIP(), []int{5} + return file_orchestrator_proto_rawDescGZIP(), []int{8} } func (x *SandboxNetworkIngressConfig) GetTrafficAccessToken() string { @@ -574,7 +723,7 @@ type SandboxCreateRequest struct { func (x *SandboxCreateRequest) Reset() { *x = SandboxCreateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_proto_msgTypes[6] + mi := &file_orchestrator_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -587,7 +736,7 @@ func (x *SandboxCreateRequest) String() string { func (*SandboxCreateRequest) ProtoMessage() {} func (x *SandboxCreateRequest) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_proto_msgTypes[6] + mi := &file_orchestrator_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -600,7 +749,7 @@ func (x *SandboxCreateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxCreateRequest.ProtoReflect.Descriptor instead. func (*SandboxCreateRequest) Descriptor() ([]byte, []int) { - return file_orchestrator_proto_rawDescGZIP(), []int{6} + return file_orchestrator_proto_rawDescGZIP(), []int{9} } func (x *SandboxCreateRequest) GetSandbox() *SandboxConfig { @@ -635,7 +784,7 @@ type SandboxCreateResponse struct { func (x *SandboxCreateResponse) Reset() { *x = SandboxCreateResponse{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_proto_msgTypes[7] + mi := &file_orchestrator_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -648,7 +797,7 @@ func (x *SandboxCreateResponse) String() string { func (*SandboxCreateResponse) ProtoMessage() {} func (x *SandboxCreateResponse) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_proto_msgTypes[7] + mi := &file_orchestrator_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -661,7 +810,7 @@ func (x *SandboxCreateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxCreateResponse.ProtoReflect.Descriptor instead. func (*SandboxCreateResponse) Descriptor() ([]byte, []int) { - return file_orchestrator_proto_rawDescGZIP(), []int{7} + return file_orchestrator_proto_rawDescGZIP(), []int{10} } func (x *SandboxCreateResponse) GetClientId() string { @@ -685,7 +834,7 @@ type SandboxUpdateRequest struct { func (x *SandboxUpdateRequest) Reset() { *x = SandboxUpdateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_proto_msgTypes[8] + mi := &file_orchestrator_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -698,7 +847,7 @@ func (x *SandboxUpdateRequest) String() string { func (*SandboxUpdateRequest) ProtoMessage() {} func (x *SandboxUpdateRequest) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_proto_msgTypes[8] + mi := &file_orchestrator_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -711,7 +860,7 @@ func (x *SandboxUpdateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxUpdateRequest.ProtoReflect.Descriptor instead. func (*SandboxUpdateRequest) Descriptor() ([]byte, []int) { - return file_orchestrator_proto_rawDescGZIP(), []int{8} + return file_orchestrator_proto_rawDescGZIP(), []int{11} } func (x *SandboxUpdateRequest) GetSandboxId() string { @@ -746,7 +895,7 @@ type SandboxDeleteRequest struct { func (x *SandboxDeleteRequest) Reset() { *x = SandboxDeleteRequest{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_proto_msgTypes[9] + mi := &file_orchestrator_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -759,7 +908,7 @@ func (x *SandboxDeleteRequest) String() string { func (*SandboxDeleteRequest) ProtoMessage() {} func (x *SandboxDeleteRequest) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_proto_msgTypes[9] + mi := &file_orchestrator_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -772,7 +921,7 @@ func (x *SandboxDeleteRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxDeleteRequest.ProtoReflect.Descriptor instead. func (*SandboxDeleteRequest) Descriptor() ([]byte, []int) { - return file_orchestrator_proto_rawDescGZIP(), []int{9} + return file_orchestrator_proto_rawDescGZIP(), []int{12} } func (x *SandboxDeleteRequest) GetSandboxId() string { @@ -795,7 +944,7 @@ type SandboxPauseRequest struct { func (x *SandboxPauseRequest) Reset() { *x = SandboxPauseRequest{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_proto_msgTypes[10] + mi := &file_orchestrator_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -808,7 +957,7 @@ func (x *SandboxPauseRequest) String() string { func (*SandboxPauseRequest) ProtoMessage() {} func (x *SandboxPauseRequest) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_proto_msgTypes[10] + mi := &file_orchestrator_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -821,7 +970,7 @@ func (x *SandboxPauseRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxPauseRequest.ProtoReflect.Descriptor instead. func (*SandboxPauseRequest) Descriptor() ([]byte, []int) { - return file_orchestrator_proto_rawDescGZIP(), []int{10} + return file_orchestrator_proto_rawDescGZIP(), []int{13} } func (x *SandboxPauseRequest) GetSandboxId() string { @@ -857,7 +1006,7 @@ type SandboxCheckpointRequest struct { func (x *SandboxCheckpointRequest) Reset() { *x = SandboxCheckpointRequest{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_proto_msgTypes[11] + mi := &file_orchestrator_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -870,7 +1019,7 @@ func (x *SandboxCheckpointRequest) String() string { func (*SandboxCheckpointRequest) ProtoMessage() {} func (x *SandboxCheckpointRequest) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_proto_msgTypes[11] + mi := &file_orchestrator_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -883,7 +1032,7 @@ func (x *SandboxCheckpointRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxCheckpointRequest.ProtoReflect.Descriptor instead. func (*SandboxCheckpointRequest) Descriptor() ([]byte, []int) { - return file_orchestrator_proto_rawDescGZIP(), []int{11} + return file_orchestrator_proto_rawDescGZIP(), []int{14} } func (x *SandboxCheckpointRequest) GetSandboxId() string { @@ -909,7 +1058,7 @@ type SandboxCheckpointResponse struct { func (x *SandboxCheckpointResponse) Reset() { *x = SandboxCheckpointResponse{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_proto_msgTypes[12] + mi := &file_orchestrator_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -922,7 +1071,7 @@ func (x *SandboxCheckpointResponse) String() string { func (*SandboxCheckpointResponse) ProtoMessage() {} func (x *SandboxCheckpointResponse) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_proto_msgTypes[12] + mi := &file_orchestrator_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -935,7 +1084,7 @@ func (x *SandboxCheckpointResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxCheckpointResponse.ProtoReflect.Descriptor instead. func (*SandboxCheckpointResponse) Descriptor() ([]byte, []int) { - return file_orchestrator_proto_rawDescGZIP(), []int{12} + return file_orchestrator_proto_rawDescGZIP(), []int{15} } type RunningSandbox struct { @@ -952,7 +1101,7 @@ type RunningSandbox struct { func (x *RunningSandbox) Reset() { *x = RunningSandbox{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_proto_msgTypes[13] + mi := &file_orchestrator_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -965,7 +1114,7 @@ func (x *RunningSandbox) String() string { func (*RunningSandbox) ProtoMessage() {} func (x *RunningSandbox) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_proto_msgTypes[13] + mi := &file_orchestrator_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -978,7 +1127,7 @@ func (x *RunningSandbox) ProtoReflect() protoreflect.Message { // Deprecated: Use RunningSandbox.ProtoReflect.Descriptor instead. func (*RunningSandbox) Descriptor() ([]byte, []int) { - return file_orchestrator_proto_rawDescGZIP(), []int{13} + return file_orchestrator_proto_rawDescGZIP(), []int{16} } func (x *RunningSandbox) GetConfig() *SandboxConfig { @@ -1020,7 +1169,7 @@ type SandboxListResponse struct { func (x *SandboxListResponse) Reset() { *x = SandboxListResponse{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_proto_msgTypes[14] + mi := &file_orchestrator_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1033,7 +1182,7 @@ func (x *SandboxListResponse) String() string { func (*SandboxListResponse) ProtoMessage() {} func (x *SandboxListResponse) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_proto_msgTypes[14] + mi := &file_orchestrator_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1046,7 +1195,7 @@ func (x *SandboxListResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxListResponse.ProtoReflect.Descriptor instead. func (*SandboxListResponse) Descriptor() ([]byte, []int) { - return file_orchestrator_proto_rawDescGZIP(), []int{14} + return file_orchestrator_proto_rawDescGZIP(), []int{17} } func (x *SandboxListResponse) GetSandboxes() []*RunningSandbox { @@ -1068,7 +1217,7 @@ type CachedBuildInfo struct { func (x *CachedBuildInfo) Reset() { *x = CachedBuildInfo{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_proto_msgTypes[15] + mi := &file_orchestrator_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1081,7 +1230,7 @@ func (x *CachedBuildInfo) String() string { func (*CachedBuildInfo) ProtoMessage() {} func (x *CachedBuildInfo) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_proto_msgTypes[15] + mi := &file_orchestrator_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1094,7 +1243,7 @@ func (x *CachedBuildInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use CachedBuildInfo.ProtoReflect.Descriptor instead. func (*CachedBuildInfo) Descriptor() ([]byte, []int) { - return file_orchestrator_proto_rawDescGZIP(), []int{15} + return file_orchestrator_proto_rawDescGZIP(), []int{18} } func (x *CachedBuildInfo) GetBuildId() string { @@ -1122,7 +1271,7 @@ type SandboxListCachedBuildsResponse struct { func (x *SandboxListCachedBuildsResponse) Reset() { *x = SandboxListCachedBuildsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_orchestrator_proto_msgTypes[16] + mi := &file_orchestrator_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1135,7 +1284,7 @@ func (x *SandboxListCachedBuildsResponse) String() string { func (*SandboxListCachedBuildsResponse) ProtoMessage() {} func (x *SandboxListCachedBuildsResponse) ProtoReflect() protoreflect.Message { - mi := &file_orchestrator_proto_msgTypes[16] + mi := &file_orchestrator_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1148,7 +1297,7 @@ func (x *SandboxListCachedBuildsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxListCachedBuildsResponse.ProtoReflect.Descriptor instead. func (*SandboxListCachedBuildsResponse) Descriptor() ([]byte, []int) { - return file_orchestrator_proto_rawDescGZIP(), []int{16} + return file_orchestrator_proto_rawDescGZIP(), []int{19} } func (x *SandboxListCachedBuildsResponse) GetBuilds() []*CachedBuildInfo { @@ -1262,133 +1411,162 @@ var file_orchestrator_proto_rawDesc = []byte{ 0x78, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x01, 0x52, 0x07, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x42, 0x0a, - 0x0a, 0x08, 0x5f, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0x8d, 0x01, 0x0a, 0x1a, 0x53, - 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, 0x67, 0x72, - 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6c, 0x6c, - 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x0c, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x43, 0x69, 0x64, 0x72, 0x73, 0x12, 0x21, - 0x0a, 0x0c, 0x64, 0x65, 0x6e, 0x69, 0x65, 0x64, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x6e, 0x69, 0x65, 0x64, 0x43, 0x69, 0x64, 0x72, - 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x6d, - 0x61, 0x69, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x6c, 0x6c, 0x6f, - 0x77, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x22, 0xb4, 0x01, 0x0a, 0x1b, 0x53, - 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x67, - 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x14, 0x74, 0x72, - 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x12, 0x74, 0x72, 0x61, 0x66, - 0x66, 0x69, 0x63, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x88, 0x01, - 0x01, 0x12, 0x2f, 0x0a, 0x11, 0x6d, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x0f, - 0x6d, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x88, - 0x01, 0x01, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x14, 0x0a, 0x12, 0x5f, - 0x6d, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x73, - 0x74, 0x22, 0xb2, 0x01, 0x0a, 0x14, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x07, 0x73, 0x61, - 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x53, 0x61, - 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x73, 0x61, 0x6e, - 0x64, 0x62, 0x6f, 0x78, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, - 0x35, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, - 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x34, 0x0a, 0x15, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, - 0x78, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0xc3, 0x01, 0x0a, - 0x14, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, - 0x6f, 0x78, 0x49, 0x64, 0x12, 0x3a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x48, 0x00, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x88, 0x01, 0x01, - 0x12, 0x38, 0x0a, 0x06, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x45, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x01, 0x52, - 0x06, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x65, - 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x65, 0x67, 0x72, 0x65, - 0x73, 0x73, 0x22, 0x35, 0x0a, 0x14, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, - 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x22, 0x70, 0x0a, 0x13, 0x53, 0x61, 0x6e, - 0x64, 0x62, 0x6f, 0x78, 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x0a, 0x08, 0x5f, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0x96, 0x01, 0x0a, 0x17, 0x53, + 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x3f, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, + 0x6d, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, + 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0x5f, 0x0a, 0x12, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, 0x65, + 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x53, + 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x48, 0x00, 0x52, 0x09, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x6f, 0x72, 0x6d, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x66, 0x6f, 0x72, 0x6d, 0x22, 0x46, 0x0a, 0x19, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x75, 0x6c, 0x65, + 0x73, 0x12, 0x29, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x13, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0xa1, 0x02, 0x0a, + 0x1a, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, + 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0a, 0x0d, 0x61, + 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0c, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x43, 0x69, 0x64, 0x72, 0x73, + 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x6e, 0x69, 0x65, 0x64, 0x5f, 0x63, 0x69, 0x64, 0x72, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x6e, 0x69, 0x65, 0x64, 0x43, 0x69, + 0x64, 0x72, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x64, + 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x6c, + 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x3c, 0x0a, 0x05, + 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x53, 0x61, + 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, 0x67, 0x72, 0x65, + 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x1a, 0x54, 0x0a, 0x0a, 0x52, 0x75, + 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x53, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, + 0x52, 0x75, 0x6c, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x22, 0xb4, 0x01, 0x0a, 0x1b, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x12, 0x35, 0x0a, 0x14, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x12, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x2f, 0x0a, 0x11, 0x6d, 0x61, 0x73, 0x6b, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x01, 0x52, 0x0f, 0x6d, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x48, 0x6f, 0x73, 0x74, 0x88, 0x01, 0x01, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x74, 0x72, 0x61, + 0x66, 0x66, 0x69, 0x63, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x22, 0xb2, 0x01, 0x0a, 0x14, 0x53, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x28, 0x0a, 0x07, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0e, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x52, 0x07, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x34, 0x0a, 0x15, + 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x49, 0x64, 0x22, 0xc3, 0x01, 0x0a, 0x14, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x3a, 0x0a, 0x08, 0x65, 0x6e, + 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x00, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, + 0x69, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x38, 0x0a, 0x06, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x45, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x48, 0x01, 0x52, 0x06, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, 0x01, + 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x42, 0x09, 0x0a, + 0x07, 0x5f, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x22, 0x35, 0x0a, 0x14, 0x53, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, - 0x1f, 0x0a, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, - 0x12, 0x19, 0x0a, 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x22, 0x54, 0x0a, 0x18, 0x53, - 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, - 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, - 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x22, + 0x70, 0x0a, 0x13, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, - 0x64, 0x22, 0x1b, 0x0a, 0x19, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xc7, - 0x01, 0x0a, 0x0e, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, - 0x78, 0x12, 0x26, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x0e, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, - 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, - 0x65, 0x12, 0x35, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x44, 0x0a, 0x13, 0x53, 0x61, 0x6e, 0x64, - 0x62, 0x6f, 0x78, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x2d, 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x53, 0x61, 0x6e, 0x64, - 0x62, 0x6f, 0x78, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x65, 0x73, 0x22, 0x71, - 0x0a, 0x0f, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, - 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x43, 0x0a, 0x0f, - 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x0e, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, - 0x65, 0x22, 0x4b, 0x0a, 0x1f, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4c, 0x69, 0x73, 0x74, - 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x06, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x42, 0x75, 0x69, - 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x32, 0xbb, - 0x03, 0x0a, 0x0e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x12, 0x37, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x53, 0x61, - 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x12, 0x34, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x12, 0x35, 0x0a, 0x05, 0x50, 0x61, 0x75, 0x73, 0x65, 0x12, 0x14, 0x2e, 0x53, 0x61, - 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x64, 0x22, 0x54, 0x0a, 0x18, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x43, 0x68, 0x65, 0x63, + 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, + 0x0a, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, + 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x62, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x22, 0x1b, 0x0a, 0x19, 0x53, 0x61, 0x6e, 0x64, 0x62, + 0x6f, 0x78, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xc7, 0x01, 0x0a, 0x0e, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, + 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x12, 0x26, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, + 0x78, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, + 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x0a, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x44, + 0x0a, 0x13, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x52, 0x75, 0x6e, 0x6e, 0x69, + 0x6e, 0x67, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x52, 0x09, 0x73, 0x61, 0x6e, 0x64, 0x62, + 0x6f, 0x78, 0x65, 0x73, 0x22, 0x71, 0x0a, 0x0f, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x42, 0x75, + 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x75, 0x69, 0x6c, 0x64, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x75, 0x69, 0x6c, 0x64, + 0x49, 0x64, 0x12, 0x43, 0x0a, 0x0f, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x4b, 0x0a, 0x1f, 0x53, 0x61, 0x6e, 0x64, 0x62, + 0x6f, 0x78, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x06, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x43, 0x61, 0x63, + 0x68, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x73, 0x32, 0xbb, 0x03, 0x0a, 0x0e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x12, 0x15, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, + 0x6f, 0x78, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x37, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x53, 0x61, 0x6e, + 0x64, 0x62, 0x6f, 0x78, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x43, 0x0a, 0x0a, 0x43, 0x68, 0x65, - 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x19, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, - 0x78, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, - 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, - 0x64, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x20, 0x2e, 0x53, 0x61, 0x6e, - 0x64, 0x62, 0x6f, 0x78, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x42, 0x75, - 0x69, 0x6c, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2f, 0x5a, 0x2d, - 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x65, 0x32, 0x62, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x69, 0x6e, 0x66, 0x72, 0x61, - 0x2f, 0x6f, 0x72, 0x63, 0x68, 0x65, 0x73, 0x74, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x34, 0x0a, 0x04, 0x4c, 0x69, 0x73, + 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x53, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x37, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x53, 0x61, 0x6e, 0x64, + 0x62, 0x6f, 0x78, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x35, 0x0a, 0x05, 0x50, 0x61, 0x75, 0x73, + 0x65, 0x12, 0x14, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x50, 0x61, 0x75, 0x73, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, + 0x43, 0x0a, 0x0a, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x19, 0x2e, + 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, + 0x6f, 0x78, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, 0x63, 0x68, + 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x1a, 0x20, 0x2e, 0x53, 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x61, + 0x63, 0x68, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x42, 0x2f, 0x5a, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x32, 0x62, 0x2d, 0x64, 0x65, 0x76, + 0x2f, 0x69, 0x6e, 0x66, 0x72, 0x61, 0x2f, 0x6f, 0x72, 0x63, 0x68, 0x65, 0x73, 0x74, 0x72, 0x61, + 0x74, 0x6f, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1403,68 +1581,78 @@ func file_orchestrator_proto_rawDescGZIP() []byte { return file_orchestrator_proto_rawDescData } -var file_orchestrator_proto_msgTypes = make([]protoimpl.MessageInfo, 19) +var file_orchestrator_proto_msgTypes = make([]protoimpl.MessageInfo, 24) var file_orchestrator_proto_goTypes = []interface{}{ (*SandboxConfig)(nil), // 0: SandboxConfig (*SandboxAutoResumeConfig)(nil), // 1: SandboxAutoResumeConfig (*SandboxVolumeMount)(nil), // 2: SandboxVolumeMount (*SandboxNetworkConfig)(nil), // 3: SandboxNetworkConfig - (*SandboxNetworkEgressConfig)(nil), // 4: SandboxNetworkEgressConfig - (*SandboxNetworkIngressConfig)(nil), // 5: SandboxNetworkIngressConfig - (*SandboxCreateRequest)(nil), // 6: SandboxCreateRequest - (*SandboxCreateResponse)(nil), // 7: SandboxCreateResponse - (*SandboxUpdateRequest)(nil), // 8: SandboxUpdateRequest - (*SandboxDeleteRequest)(nil), // 9: SandboxDeleteRequest - (*SandboxPauseRequest)(nil), // 10: SandboxPauseRequest - (*SandboxCheckpointRequest)(nil), // 11: SandboxCheckpointRequest - (*SandboxCheckpointResponse)(nil), // 12: SandboxCheckpointResponse - (*RunningSandbox)(nil), // 13: RunningSandbox - (*SandboxListResponse)(nil), // 14: SandboxListResponse - (*CachedBuildInfo)(nil), // 15: CachedBuildInfo - (*SandboxListCachedBuildsResponse)(nil), // 16: SandboxListCachedBuildsResponse - nil, // 17: SandboxConfig.EnvVarsEntry - nil, // 18: SandboxConfig.MetadataEntry - (*timestamppb.Timestamp)(nil), // 19: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 20: google.protobuf.Empty + (*SandboxNetworkTransform)(nil), // 4: SandboxNetworkTransform + (*SandboxNetworkRule)(nil), // 5: SandboxNetworkRule + (*SandboxNetworkDomainRules)(nil), // 6: SandboxNetworkDomainRules + (*SandboxNetworkEgressConfig)(nil), // 7: SandboxNetworkEgressConfig + (*SandboxNetworkIngressConfig)(nil), // 8: SandboxNetworkIngressConfig + (*SandboxCreateRequest)(nil), // 9: SandboxCreateRequest + (*SandboxCreateResponse)(nil), // 10: SandboxCreateResponse + (*SandboxUpdateRequest)(nil), // 11: SandboxUpdateRequest + (*SandboxDeleteRequest)(nil), // 12: SandboxDeleteRequest + (*SandboxPauseRequest)(nil), // 13: SandboxPauseRequest + (*SandboxCheckpointRequest)(nil), // 14: SandboxCheckpointRequest + (*SandboxCheckpointResponse)(nil), // 15: SandboxCheckpointResponse + (*RunningSandbox)(nil), // 16: RunningSandbox + (*SandboxListResponse)(nil), // 17: SandboxListResponse + (*CachedBuildInfo)(nil), // 18: CachedBuildInfo + (*SandboxListCachedBuildsResponse)(nil), // 19: SandboxListCachedBuildsResponse + nil, // 20: SandboxConfig.EnvVarsEntry + nil, // 21: SandboxConfig.MetadataEntry + nil, // 22: SandboxNetworkTransform.HeadersEntry + nil, // 23: SandboxNetworkEgressConfig.RulesEntry + (*timestamppb.Timestamp)(nil), // 24: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 25: google.protobuf.Empty } var file_orchestrator_proto_depIdxs = []int32{ - 17, // 0: SandboxConfig.env_vars:type_name -> SandboxConfig.EnvVarsEntry - 18, // 1: SandboxConfig.metadata:type_name -> SandboxConfig.MetadataEntry + 20, // 0: SandboxConfig.env_vars:type_name -> SandboxConfig.EnvVarsEntry + 21, // 1: SandboxConfig.metadata:type_name -> SandboxConfig.MetadataEntry 3, // 2: SandboxConfig.network:type_name -> SandboxNetworkConfig 2, // 3: SandboxConfig.volumeMounts:type_name -> SandboxVolumeMount 1, // 4: SandboxConfig.auto_resume:type_name -> SandboxAutoResumeConfig - 4, // 5: SandboxNetworkConfig.egress:type_name -> SandboxNetworkEgressConfig - 5, // 6: SandboxNetworkConfig.ingress:type_name -> SandboxNetworkIngressConfig - 0, // 7: SandboxCreateRequest.sandbox:type_name -> SandboxConfig - 19, // 8: SandboxCreateRequest.start_time:type_name -> google.protobuf.Timestamp - 19, // 9: SandboxCreateRequest.end_time:type_name -> google.protobuf.Timestamp - 19, // 10: SandboxUpdateRequest.end_time:type_name -> google.protobuf.Timestamp - 4, // 11: SandboxUpdateRequest.egress:type_name -> SandboxNetworkEgressConfig - 0, // 12: RunningSandbox.config:type_name -> SandboxConfig - 19, // 13: RunningSandbox.start_time:type_name -> google.protobuf.Timestamp - 19, // 14: RunningSandbox.end_time:type_name -> google.protobuf.Timestamp - 13, // 15: SandboxListResponse.sandboxes:type_name -> RunningSandbox - 19, // 16: CachedBuildInfo.expiration_time:type_name -> google.protobuf.Timestamp - 15, // 17: SandboxListCachedBuildsResponse.builds:type_name -> CachedBuildInfo - 6, // 18: SandboxService.Create:input_type -> SandboxCreateRequest - 8, // 19: SandboxService.Update:input_type -> SandboxUpdateRequest - 20, // 20: SandboxService.List:input_type -> google.protobuf.Empty - 9, // 21: SandboxService.Delete:input_type -> SandboxDeleteRequest - 10, // 22: SandboxService.Pause:input_type -> SandboxPauseRequest - 11, // 23: SandboxService.Checkpoint:input_type -> SandboxCheckpointRequest - 20, // 24: SandboxService.ListCachedBuilds:input_type -> google.protobuf.Empty - 7, // 25: SandboxService.Create:output_type -> SandboxCreateResponse - 20, // 26: SandboxService.Update:output_type -> google.protobuf.Empty - 14, // 27: SandboxService.List:output_type -> SandboxListResponse - 20, // 28: SandboxService.Delete:output_type -> google.protobuf.Empty - 20, // 29: SandboxService.Pause:output_type -> google.protobuf.Empty - 12, // 30: SandboxService.Checkpoint:output_type -> SandboxCheckpointResponse - 16, // 31: SandboxService.ListCachedBuilds:output_type -> SandboxListCachedBuildsResponse - 25, // [25:32] is the sub-list for method output_type - 18, // [18:25] is the sub-list for method input_type - 18, // [18:18] is the sub-list for extension type_name - 18, // [18:18] is the sub-list for extension extendee - 0, // [0:18] is the sub-list for field type_name + 7, // 5: SandboxNetworkConfig.egress:type_name -> SandboxNetworkEgressConfig + 8, // 6: SandboxNetworkConfig.ingress:type_name -> SandboxNetworkIngressConfig + 22, // 7: SandboxNetworkTransform.headers:type_name -> SandboxNetworkTransform.HeadersEntry + 4, // 8: SandboxNetworkRule.transform:type_name -> SandboxNetworkTransform + 5, // 9: SandboxNetworkDomainRules.rules:type_name -> SandboxNetworkRule + 23, // 10: SandboxNetworkEgressConfig.rules:type_name -> SandboxNetworkEgressConfig.RulesEntry + 0, // 11: SandboxCreateRequest.sandbox:type_name -> SandboxConfig + 24, // 12: SandboxCreateRequest.start_time:type_name -> google.protobuf.Timestamp + 24, // 13: SandboxCreateRequest.end_time:type_name -> google.protobuf.Timestamp + 24, // 14: SandboxUpdateRequest.end_time:type_name -> google.protobuf.Timestamp + 7, // 15: SandboxUpdateRequest.egress:type_name -> SandboxNetworkEgressConfig + 0, // 16: RunningSandbox.config:type_name -> SandboxConfig + 24, // 17: RunningSandbox.start_time:type_name -> google.protobuf.Timestamp + 24, // 18: RunningSandbox.end_time:type_name -> google.protobuf.Timestamp + 16, // 19: SandboxListResponse.sandboxes:type_name -> RunningSandbox + 24, // 20: CachedBuildInfo.expiration_time:type_name -> google.protobuf.Timestamp + 18, // 21: SandboxListCachedBuildsResponse.builds:type_name -> CachedBuildInfo + 6, // 22: SandboxNetworkEgressConfig.RulesEntry.value:type_name -> SandboxNetworkDomainRules + 9, // 23: SandboxService.Create:input_type -> SandboxCreateRequest + 11, // 24: SandboxService.Update:input_type -> SandboxUpdateRequest + 25, // 25: SandboxService.List:input_type -> google.protobuf.Empty + 12, // 26: SandboxService.Delete:input_type -> SandboxDeleteRequest + 13, // 27: SandboxService.Pause:input_type -> SandboxPauseRequest + 14, // 28: SandboxService.Checkpoint:input_type -> SandboxCheckpointRequest + 25, // 29: SandboxService.ListCachedBuilds:input_type -> google.protobuf.Empty + 10, // 30: SandboxService.Create:output_type -> SandboxCreateResponse + 25, // 31: SandboxService.Update:output_type -> google.protobuf.Empty + 17, // 32: SandboxService.List:output_type -> SandboxListResponse + 25, // 33: SandboxService.Delete:output_type -> google.protobuf.Empty + 25, // 34: SandboxService.Pause:output_type -> google.protobuf.Empty + 15, // 35: SandboxService.Checkpoint:output_type -> SandboxCheckpointResponse + 19, // 36: SandboxService.ListCachedBuilds:output_type -> SandboxListCachedBuildsResponse + 30, // [30:37] is the sub-list for method output_type + 23, // [23:30] is the sub-list for method input_type + 23, // [23:23] is the sub-list for extension type_name + 23, // [23:23] is the sub-list for extension extendee + 0, // [0:23] is the sub-list for field type_name } func init() { file_orchestrator_proto_init() } @@ -1522,7 +1710,7 @@ func file_orchestrator_proto_init() { } } file_orchestrator_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxNetworkEgressConfig); i { + switch v := v.(*SandboxNetworkTransform); i { case 0: return &v.state case 1: @@ -1534,7 +1722,7 @@ func file_orchestrator_proto_init() { } } file_orchestrator_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxNetworkIngressConfig); i { + switch v := v.(*SandboxNetworkRule); i { case 0: return &v.state case 1: @@ -1546,7 +1734,7 @@ func file_orchestrator_proto_init() { } } file_orchestrator_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxCreateRequest); i { + switch v := v.(*SandboxNetworkDomainRules); i { case 0: return &v.state case 1: @@ -1558,7 +1746,7 @@ func file_orchestrator_proto_init() { } } file_orchestrator_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxCreateResponse); i { + switch v := v.(*SandboxNetworkEgressConfig); i { case 0: return &v.state case 1: @@ -1570,7 +1758,7 @@ func file_orchestrator_proto_init() { } } file_orchestrator_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxUpdateRequest); i { + switch v := v.(*SandboxNetworkIngressConfig); i { case 0: return &v.state case 1: @@ -1582,7 +1770,7 @@ func file_orchestrator_proto_init() { } } file_orchestrator_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxDeleteRequest); i { + switch v := v.(*SandboxCreateRequest); i { case 0: return &v.state case 1: @@ -1594,7 +1782,7 @@ func file_orchestrator_proto_init() { } } file_orchestrator_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxPauseRequest); i { + switch v := v.(*SandboxCreateResponse); i { case 0: return &v.state case 1: @@ -1606,7 +1794,7 @@ func file_orchestrator_proto_init() { } } file_orchestrator_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxCheckpointRequest); i { + switch v := v.(*SandboxUpdateRequest); i { case 0: return &v.state case 1: @@ -1618,7 +1806,7 @@ func file_orchestrator_proto_init() { } } file_orchestrator_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxCheckpointResponse); i { + switch v := v.(*SandboxDeleteRequest); i { case 0: return &v.state case 1: @@ -1630,7 +1818,7 @@ func file_orchestrator_proto_init() { } } file_orchestrator_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RunningSandbox); i { + switch v := v.(*SandboxPauseRequest); i { case 0: return &v.state case 1: @@ -1642,7 +1830,7 @@ func file_orchestrator_proto_init() { } } file_orchestrator_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SandboxListResponse); i { + switch v := v.(*SandboxCheckpointRequest); i { case 0: return &v.state case 1: @@ -1654,7 +1842,7 @@ func file_orchestrator_proto_init() { } } file_orchestrator_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CachedBuildInfo); i { + switch v := v.(*SandboxCheckpointResponse); i { case 0: return &v.state case 1: @@ -1666,6 +1854,42 @@ func file_orchestrator_proto_init() { } } file_orchestrator_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RunningSandbox); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_orchestrator_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SandboxListResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_orchestrator_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CachedBuildInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_orchestrator_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SandboxListCachedBuildsResponse); i { case 0: return &v.state @@ -1682,13 +1906,14 @@ func file_orchestrator_proto_init() { file_orchestrator_proto_msgTypes[3].OneofWrappers = []interface{}{} file_orchestrator_proto_msgTypes[5].OneofWrappers = []interface{}{} file_orchestrator_proto_msgTypes[8].OneofWrappers = []interface{}{} + file_orchestrator_proto_msgTypes[11].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_orchestrator_proto_rawDesc, NumEnums: 0, - NumMessages: 19, + NumMessages: 24, NumExtensions: 0, NumServices: 1, }, diff --git a/spec/openapi.yml b/spec/openapi.yml index f5c8960ed7..c201c997ff 100644 --- a/spec/openapi.yml +++ b/spec/openapi.yml @@ -282,6 +282,36 @@ components: maskRequestHost: type: string description: Specify host mask which will be used for all sandbox requests + rules: + type: object + description: > + Per-domain transform rules applied to matching egress HTTP/HTTPS requests. + Keys are domains (e.g. "api.example.com", "example.com"). + A domain listed here is not automatically allowed - use allowOut to permit the traffic. + additionalProperties: + type: array + items: + $ref: '#/components/schemas/SandboxNetworkRule' + + SandboxNetworkRule: + type: object + description: Transform rule applied to egress requests matching a domain pattern. + properties: + transform: + $ref: '#/components/schemas/SandboxNetworkTransform' + + SandboxNetworkTransform: + type: object + description: Transformations applied to matching egress requests before forwarding. + properties: + headers: + type: object + description: > + HTTP headers to inject or override in matching requests. + An existing header with the same name is replaced. Values are plain strings; + secret resolution happens client-side before sending to the API. + additionalProperties: + type: string SandboxAutoResumeEnabled: type: boolean @@ -2395,6 +2425,13 @@ paths: description: List of denied CIDR blocks or IP addresses for egress traffic. Domain names are not supported for deny rules. items: type: string + rules: + type: object + description: Per-domain transform rules. Replaces all existing rules when provided. + additionalProperties: + type: array + items: + $ref: '#/components/schemas/SandboxNetworkRule' allow_internet_access: type: boolean description: diff --git a/tests/integration/internal/api/generated.go b/tests/integration/internal/api/generated.go index b43f96ac59..a202f60802 100644 --- a/tests/integration/internal/api/generated.go +++ b/tests/integration/internal/api/generated.go @@ -894,6 +894,21 @@ type SandboxNetworkConfig struct { // MaskRequestHost Specify host mask which will be used for all sandbox requests MaskRequestHost *string `json:"maskRequestHost,omitempty"` + + // Rules Per-domain transform rules applied to matching egress HTTP/HTTPS requests. Keys are domains (e.g. "api.example.com", "example.com"). A domain listed here is not automatically allowed - use allowOut to permit the traffic. + Rules *map[string][]SandboxNetworkRule `json:"rules,omitempty"` +} + +// SandboxNetworkRule Transform rule applied to egress requests matching a domain pattern. +type SandboxNetworkRule struct { + // Transform Transformations applied to matching egress requests before forwarding. + Transform *SandboxNetworkTransform `json:"transform,omitempty"` +} + +// SandboxNetworkTransform Transformations applied to matching egress requests before forwarding. +type SandboxNetworkTransform struct { + // Headers HTTP headers to inject or override in matching requests. An existing header with the same name is replaced. Values are plain strings; secret resolution happens client-side before sending to the API. + Headers *map[string]string `json:"headers,omitempty"` } // SandboxOnTimeout Action taken when the sandbox times out. @@ -1447,6 +1462,9 @@ type PutSandboxesSandboxIDNetworkJSONBody struct { // DenyOut List of denied CIDR blocks or IP addresses for egress traffic. Domain names are not supported for deny rules. DenyOut *[]string `json:"denyOut,omitempty"` + + // Rules Per-domain transform rules. Replaces all existing rules when provided. + Rules *map[string][]SandboxNetworkRule `json:"rules,omitempty"` } // PostSandboxesSandboxIDRefreshesJSONBody defines parameters for PostSandboxesSandboxIDRefreshes.