diff --git a/cli/testdata/coder_provisioner_list_--output_json.golden b/cli/testdata/coder_provisioner_list_--output_json.golden index 13d2e25018..93caf623df 100644 --- a/cli/testdata/coder_provisioner_list_--output_json.golden +++ b/cli/testdata/coder_provisioner_list_--output_json.golden @@ -7,7 +7,7 @@ "last_seen_at": "====[timestamp]=====", "name": "test-daemon", "version": "v0.0.0-devel", - "api_version": "1.17", + "api_version": "1.18", "provisioners": [ "echo" ], diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 9b520ca8ce..61a1d569d3 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -18895,7 +18895,7 @@ const docTemplate = `{ "type": "object", "properties": { "id": { - "description": "ID identifies the request for response ordering. Websocket response\nIDs are monotonically increasing and may exceed the request ID when\nserver-side events trigger additional renders.", + "description": "ID identifies the request. The response contains the same\nID so that the client can match it to the request.", "type": "integer" }, "inputs": { @@ -18928,12 +18928,6 @@ const docTemplate = `{ "items": { "$ref": "#/definitions/codersdk.PreviewParameter" } - }, - "secret_requirements": { - "type": "array", - "items": { - "$ref": "#/definitions/codersdk.SecretRequirementStatus" - } } } }, @@ -22554,10 +22548,6 @@ const docTemplate = `{ "properties": { "parameter_mismatch": { "type": "boolean" - }, - "secret_mismatch": { - "description": "SecretMismatch is true when the active template version declares\n` + "`" + `coder_secret` + "`" + ` requirements that the workspace owner's secrets do not\nsatisfy.", - "type": "boolean" } } }, @@ -22778,23 +22768,6 @@ const docTemplate = `{ } } }, - "codersdk.SecretRequirementStatus": { - "type": "object", - "properties": { - "env": { - "type": "string" - }, - "file": { - "type": "string" - }, - "help_message": { - "type": "string" - }, - "satisfied": { - "type": "boolean" - } - } - }, "codersdk.ServerSentEvent": { "type": "object", "properties": { diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 5baa2bd081..0834255679 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -17163,7 +17163,7 @@ "type": "object", "properties": { "id": { - "description": "ID identifies the request for response ordering. Websocket response\nIDs are monotonically increasing and may exceed the request ID when\nserver-side events trigger additional renders.", + "description": "ID identifies the request. The response contains the same\nID so that the client can match it to the request.", "type": "integer" }, "inputs": { @@ -17196,12 +17196,6 @@ "items": { "$ref": "#/definitions/codersdk.PreviewParameter" } - }, - "secret_requirements": { - "type": "array", - "items": { - "$ref": "#/definitions/codersdk.SecretRequirementStatus" - } } } }, @@ -20687,10 +20681,6 @@ "properties": { "parameter_mismatch": { "type": "boolean" - }, - "secret_mismatch": { - "description": "SecretMismatch is true when the active template version declares\n`coder_secret` requirements that the workspace owner's secrets do not\nsatisfy.", - "type": "boolean" } } }, @@ -20911,23 +20901,6 @@ } } }, - "codersdk.SecretRequirementStatus": { - "type": "object", - "properties": { - "env": { - "type": "string" - }, - "file": { - "type": "string" - }, - "help_message": { - "type": "string" - }, - "satisfied": { - "type": "boolean" - } - } - }, "codersdk.ServerSentEvent": { "type": "object", "properties": { diff --git a/coderd/autobuild/lifecycle_executor.go b/coderd/autobuild/lifecycle_executor.go index c616db0ab3..84fff375e0 100644 --- a/coderd/autobuild/lifecycle_executor.go +++ b/coderd/autobuild/lifecycle_executor.go @@ -343,7 +343,6 @@ func (e *Executor) runOnce(t time.Time) Stats { SetLastWorkspaceBuildJobInTx(&latestJob). Experiments(e.experiments). Reason(reason). - Logger(log.Named("wsbuilder")). BuildMetrics(e.workspaceBuilderMetrics) log.Debug(e.ctx, "auto building workspace", slog.F("transition", nextTransition)) if nextTransition == database.WorkspaceTransitionStart && diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index b0c2703934..b1464c5ca6 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -246,7 +246,6 @@ var ( rbac.ResourceWorkspaceAgentDevcontainers.Type: {policy.ActionCreate}, // Provisionerd creates usage events rbac.ResourceUsageEvent.Type: {policy.ActionCreate}, - rbac.ResourceUserSecret.Type: {policy.ActionRead}, }), User: []rbac.Permission{}, ByOrgID: map[string]rbac.OrgPermissions{}, @@ -271,7 +270,6 @@ var ( rbac.ResourceTask.Type: {policy.ActionRead, policy.ActionUpdate}, rbac.ResourceTemplate.Type: {policy.ActionRead, policy.ActionUpdate}, rbac.ResourceUser.Type: {policy.ActionRead}, - rbac.ResourceUserSecret.Type: {policy.ActionRead}, rbac.ResourceWorkspace.Type: {policy.ActionDelete, policy.ActionRead, policy.ActionUpdate, policy.ActionWorkspaceStart, policy.ActionWorkspaceStop}, rbac.ResourceWorkspaceDormant.Type: {policy.ActionDelete, policy.ActionRead, policy.ActionUpdate, policy.ActionWorkspaceStop}, }), diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 8a6d8393b1..9004ff428e 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -6841,19 +6841,6 @@ func TestAuthorizeProvisionerJob_SystemFastPath(t *testing.T) { }) } -func TestAsAutostart(t *testing.T) { - t.Parallel() - - ctx := dbauthz.AsAutostart(context.Background()) - actor, ok := dbauthz.ActorFromContext(ctx) - require.True(t, ok, "actor must be present") - - auth := rbac.NewStrictCachingAuthorizer(prometheus.NewRegistry()) - - err := auth.Authorize(ctx, actor, policy.ActionRead, rbac.ResourceUserSecret.WithOwner(uuid.NewString())) - require.NoError(t, err, "user secret metadata read should be allowed") -} - func TestAsChatd(t *testing.T) { t.Parallel() diff --git a/coderd/dynamicparameters/render.go b/coderd/dynamicparameters/render.go index d6e3625c9e..aa2fc04bd8 100644 --- a/coderd/dynamicparameters/render.go +++ b/coderd/dynamicparameters/render.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "io/fs" + "log/slog" "sync" "time" @@ -12,27 +13,14 @@ import ( "github.com/zclconf/go-cty/cty" "golang.org/x/xerrors" - "cdr.dev/slog/v3" "github.com/coder/coder/v2/apiversion" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/files" - "github.com/coder/coder/v2/codersdk" "github.com/coder/preview" previewtypes "github.com/coder/preview/types" ) -// RenderResult is the structured output of Renderer.Render. The outer -// pointer is always non-nil; inner fields may be nil. -// SecretRequirements is nil when no coder_secret blocks are declared, -// when fetch was forbidden, or when fetch failed. Output may be nil -// when underlying rendering fails (matches preview.Preview's existing -// convention). -type RenderResult struct { - Output *preview.Output - SecretRequirements []codersdk.SecretRequirementStatus -} - // Renderer is able to execute and evaluate terraform with the given inputs. // It may use the database to fetch additional state, such as a user's groups, // roles, etc. Therefore, it requires an authenticated `ctx`. @@ -40,40 +28,17 @@ type RenderResult struct { // 'Close()' **must** be called once the renderer is no longer needed. // Forgetting to do so will result in a memory leak. type Renderer interface { - Render(ctx context.Context, ownerID uuid.UUID, values map[string]string, opts ...RenderOption) (*RenderResult, hcl.Diagnostics) + Render(ctx context.Context, ownerID uuid.UUID, values map[string]string) (*preview.Output, hcl.Diagnostics) Close() } var ErrTemplateVersionNotReady = xerrors.New("template version job not finished") -// RenderOption configures optional behavior for Renderer.Render. -type RenderOption func(*renderOptions) - -type renderOptions struct { - includeSecretRequirements bool -} - -// IncludeSecretRequirements returns structured secret-requirement statuses and -// diagnostics for the rendered template. -func IncludeSecretRequirements() RenderOption { - return func(o *renderOptions) { - o.includeSecretRequirements = true - } -} - -// Diagnostic extra codes for secret-requirement validation. -const ( - DiagCodeMissingSecret = "missing_secret" - DiagCodeOwnerSecretsFetchFailed = "owner_secrets_fetch_failed" - DiagCodeSecretValidationForbidden = "secret_validation_forbidden" -) - // loader is used to load the necessary coder objects for rendering a template // version's parameters. The output is a Renderer, which is the object that uses // the cached objects to render the template version's parameters. type loader struct { templateVersionID uuid.UUID - logger slog.Logger // cache of objects templateVersion *database.TemplateVersion @@ -125,13 +90,6 @@ func WithTerraformValues(values database.TemplateVersionTerraformValue) func(r * } } -// WithLogger sets the logger used by the renderer. -func WithLogger(logger slog.Logger) func(r *loader) { - return func(r *loader) { - r.logger = logger - } -} - func (r *loader) loadData(ctx context.Context, db database.Store) error { if r.templateVersion == nil { tv, err := db.GetTemplateVersionByID(ctx, r.templateVersionID) @@ -245,14 +203,12 @@ func (r *loader) dynamicRenderer(ctx context.Context, db database.Store, cache * closeFiles = false // Caller will have to call close return &dynamicRenderer{ - data: r, - templateFS: templateFS, - db: db, - logger: r.logger, - ownerErrors: make(map[uuid.UUID]error), - ownerSecretErrors: make(map[uuid.UUID]error), - close: cache.Close, - tfvarValues: tfVarValues, + data: r, + templateFS: templateFS, + db: db, + ownerErrors: make(map[uuid.UUID]error), + close: cache.Close, + tfvarValues: tfVarValues, }, nil } @@ -260,26 +216,16 @@ type dynamicRenderer struct { db database.Store data *loader templateFS fs.FS - logger slog.Logger ownerErrors map[uuid.UUID]error currentOwner *previewtypes.WorkspaceOwner - - // ownerSecretErrors caches NotAuthorized denials per owner. - ownerSecretErrors map[uuid.UUID]error - - tfvarValues map[string]cty.Value + tfvarValues map[string]cty.Value once sync.Once close func() } -func (r *dynamicRenderer) Render(ctx context.Context, ownerID uuid.UUID, values map[string]string, opts ...RenderOption) (*RenderResult, hcl.Diagnostics) { - options := renderOptions{} - for _, opt := range opts { - opt(&options) - } - +func (r *dynamicRenderer) Render(ctx context.Context, ownerID uuid.UUID, values map[string]string) (*preview.Output, hcl.Diagnostics) { // Always start with the cached error, if we have one. ownerErr := r.ownerErrors[ownerID] if ownerErr == nil { @@ -288,7 +234,7 @@ func (r *dynamicRenderer) Render(ctx context.Context, ownerID uuid.UUID, values if ownerErr != nil || r.currentOwner == nil { r.ownerErrors[ownerID] = ownerErr - return &RenderResult{}, hcl.Diagnostics{ + return nil, hcl.Diagnostics{ { Severity: hcl.DiagError, Summary: "Failed to fetch workspace owner", @@ -305,122 +251,13 @@ func (r *dynamicRenderer) Render(ctx context.Context, ownerID uuid.UUID, values ParameterValues: values, Owner: *r.currentOwner, TFVars: r.tfvarValues, - // Leave Logger nil so preview discards parser logs. Returning - // those logs to callers would be useful, but they may be large. + // Do not emit parser logs to coderd output logs. + // TODO: Returning this logs in the output would benefit the caller. + // Unsure how large the logs can be, so for now we just discard them. + Logger: slog.New(slog.DiscardHandler), } - output, diags := preview.Preview(ctx, input, r.templateFS) - if output == nil { - return &RenderResult{}, diags - } - - var secretRequirements []codersdk.SecretRequirementStatus - if options.includeSecretRequirements && len(output.SecretRequirements) > 0 { - var secretDiags hcl.Diagnostics - secretRequirements, secretDiags = r.checkSecretRequirements(ctx, ownerID, output.SecretRequirements) - diags = diags.Extend(secretDiags) - } - - return &RenderResult{ - Output: output, - SecretRequirements: secretRequirements, - }, diags -} - -// checkSecretRequirements returns structured requirement statuses. Callers -// without user_secret:read on the owner get a single -// secret_validation_forbidden warning instead, to avoid leaking the target's -// secret names via structured status presence. -func (r *dynamicRenderer) checkSecretRequirements(ctx context.Context, ownerID uuid.UUID, reqs []previewtypes.SecretRequirement) ([]codersdk.SecretRequirementStatus, hcl.Diagnostics) { - secrets, err := r.getOwnerSecrets(ctx, ownerID) - if err != nil { - if dbauthz.IsNotAuthorizedError(err) { - // Warning keeps the Create Workspace button enabled. - return nil, hcl.Diagnostics{{ - Severity: hcl.DiagWarning, - Summary: "Cannot validate secret requirements", - Detail: "You are not permitted to read secret metadata for this user. The workspace may fail to build if required secrets are not set.", - Extra: previewtypes.DiagnosticExtra{ - Code: DiagCodeSecretValidationForbidden, - }, - }} - } - r.logger.Warn(ctx, "failed to fetch owner secrets for secret-requirement validation", - slog.F("owner_id", ownerID), - slog.Error(err), - ) - return nil, hcl.Diagnostics{{ - Severity: hcl.DiagError, - Summary: "Failed to fetch owner secrets", - Detail: "Could not validate template secret requirements. Please try again.", - Extra: previewtypes.DiagnosticExtra{ - Code: DiagCodeOwnerSecretsFetchFailed, - }, - }} - } - - envSet := make(map[string]struct{}, len(secrets)) - fileSet := make(map[string]struct{}, len(secrets)) - for _, s := range secrets { - if s.EnvName != "" { - envSet[s.EnvName] = struct{}{} - } - if s.FilePath != "" { - fileSet[s.FilePath] = struct{}{} - } - } - - statuses := make([]codersdk.SecretRequirementStatus, 0, len(reqs)) - type secretRequirementDedupKey struct { - env string - file string - } - seen := make(map[secretRequirementDedupKey]int, len(reqs)) - for _, req := range reqs { - kind := secretRequirementKind(req.Env, req.File) - if kind == "" { - // Defensive: SecretFromBlock should reject invalid inputs upstream. - continue - } - - var env string - var file string - satisfied := false - switch kind { - case secretRequirementKindEnv: - env = req.Env - _, satisfied = envSet[req.Env] - case secretRequirementKindFile: - file = req.File - _, satisfied = fileSet[req.File] - } - - // Dedup by Env/File. On collision, keep the - // lexicographically smallest non-empty HelpMessage. This is - // deterministic across runs; preview's SortSecretRequirements - // sorts on (Env, File) and does not guarantee a stable order - // when multiple coder_secret blocks declare the same value, so - // we cannot rely on "first source wins." - key := secretRequirementDedupKey{ - env: env, - file: file, - } - if i, ok := seen[key]; ok { - statuses[i].Satisfied = statuses[i].Satisfied || satisfied - if req.HelpMessage != "" && (statuses[i].HelpMessage == "" || req.HelpMessage < statuses[i].HelpMessage) { - statuses[i].HelpMessage = req.HelpMessage - } - continue - } - seen[key] = len(statuses) - statuses = append(statuses, codersdk.SecretRequirementStatus{ - Env: env, - File: file, - HelpMessage: req.HelpMessage, - Satisfied: satisfied, - }) - } - return statuses, nil + return preview.Preview(ctx, input, r.templateFS) } func (r *dynamicRenderer) getWorkspaceOwnerData(ctx context.Context, ownerID uuid.UUID) error { @@ -437,23 +274,6 @@ func (r *dynamicRenderer) getWorkspaceOwnerData(ctx context.Context, ownerID uui return nil } -// getOwnerSecrets fetches the owner's secrets under the caller's auth -// context. Only NotAuthorized denials are cached; successes re-fetch so -// newly-created secrets are picked up on the next render. -func (r *dynamicRenderer) getOwnerSecrets(ctx context.Context, ownerID uuid.UUID) ([]database.ListUserSecretsRow, error) { - if err, cached := r.ownerSecretErrors[ownerID]; cached { - return nil, err - } - rows, err := r.db.ListUserSecrets(ctx, ownerID) - if err != nil { - if dbauthz.IsNotAuthorizedError(err) { - r.ownerSecretErrors[ownerID] = err - } - return nil, err - } - return rows, nil -} - func (r *dynamicRenderer) Close() { r.once.Do(r.close) } diff --git a/coderd/dynamicparameters/render_internal_test.go b/coderd/dynamicparameters/render_internal_test.go deleted file mode 100644 index 9da5744ddf..0000000000 --- a/coderd/dynamicparameters/render_internal_test.go +++ /dev/null @@ -1,394 +0,0 @@ -package dynamicparameters - -import ( - "context" - "os" - "path/filepath" - "sync" - "testing" - - "github.com/google/uuid" - "github.com/hashicorp/hcl/v2" - "github.com/stretchr/testify/require" - "golang.org/x/xerrors" - - "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/database/dbauthz" - "github.com/coder/coder/v2/coderd/database/dbgen" - "github.com/coder/coder/v2/coderd/database/dbtestutil" - "github.com/coder/coder/v2/codersdk" - previewtypes "github.com/coder/preview/types" -) - -// newTestRenderer builds a dynamicRenderer backed by the given testdata -// fixture. The caller must seed an org and member row. -func newTestRenderer(t *testing.T, db database.Store, orgID uuid.UUID, fixture string) *dynamicRenderer { - t.Helper() - return &dynamicRenderer{ - db: db, - templateFS: os.DirFS(filepath.Join("testdata", fixture)), - ownerErrors: make(map[uuid.UUID]error), - ownerSecretErrors: make(map[uuid.UUID]error), - data: &loader{ - templateVersion: &database.TemplateVersion{ - OrganizationID: orgID, - }, - terraformValues: &database.TemplateVersionTerraformValue{}, - }, - close: func() {}, - } -} - -// seedOwner creates a user and org member so WorkspaceOwner resolves. -func seedOwner(t *testing.T, db database.Store, orgID uuid.UUID) database.User { - t.Helper() - u := dbgen.User(t, db, database.User{}) - dbgen.OrganizationMember(t, db, database.OrganizationMember{ - OrganizationID: orgID, - UserID: u.ID, - }) - return u -} - -func TestDynamicRender_MissingSecretRequirement(t *testing.T) { - t.Parallel() - - db, _ := dbtestutil.NewDB(t) - ctx := t.Context() - org := dbgen.Organization(t, db, database.Organization{}) - owner := seedOwner(t, db, org.ID) - - renderer := newTestRenderer(t, db, org.ID, "secret_required") - defer renderer.Close() - - // Owner has no secrets; the GITHUB_TOKEN requirement is unmet. - out, diags := renderer.Render(ctx, owner.ID, nil, IncludeSecretRequirements()) - require.NotNil(t, out) - require.NotNil(t, out.Output) - requireNoMissingSecret(t, diags) - require.Equal(t, []codersdk.SecretRequirementStatus{{ - Env: "GITHUB_TOKEN", - HelpMessage: "Add a GitHub PAT with env=GITHUB_TOKEN", - Satisfied: false, - }}, out.SecretRequirements) - - // The same renderer must pick up a newly-created secret on the - // next render, without a reload. - _ = dbgen.UserSecret(t, db, database.UserSecret{ - UserID: owner.ID, - Name: "github_token", - EnvName: "GITHUB_TOKEN", - }) - - out, diags2 := renderer.Render(ctx, owner.ID, nil, IncludeSecretRequirements()) - requireNoMissingSecret(t, diags2) - require.Equal(t, []codersdk.SecretRequirementStatus{{ - Env: "GITHUB_TOKEN", - HelpMessage: "Add a GitHub PAT with env=GITHUB_TOKEN", - Satisfied: true, - }}, out.SecretRequirements) -} - -func TestDynamicRender_ConditionalSecretRequirement(t *testing.T) { - t.Parallel() - - db, _ := dbtestutil.NewDB(t) - ctx := t.Context() - org := dbgen.Organization(t, db, database.Organization{}) - owner := seedOwner(t, db, org.ID) - - renderer := newTestRenderer(t, db, org.ID, "secret_conditional") - defer renderer.Close() - - // Block inactive: no validation. - out, diags := renderer.Render(ctx, owner.ID, map[string]string{"use_github": "false"}, IncludeSecretRequirements()) - requireNoMissingSecret(t, diags) - require.Nil(t, out.SecretRequirements) - - // Block active: requirement surfaces. - out, diags = renderer.Render(ctx, owner.ID, map[string]string{"use_github": "true"}, IncludeSecretRequirements()) - requireNoMissingSecret(t, diags) - require.Equal(t, []codersdk.SecretRequirementStatus{{ - Env: "GITHUB_TOKEN", - HelpMessage: "Add a GitHub PAT", - Satisfied: false, - }}, out.SecretRequirements) -} - -func TestDynamicRender_SingleSecretSatisfiesEnvAndFile(t *testing.T) { - t.Parallel() - - db, _ := dbtestutil.NewDB(t) - ctx := t.Context() - org := dbgen.Organization(t, db, database.Organization{}) - owner := seedOwner(t, db, org.ID) - - // One row must satisfy both an env and a file requirement: the - // check builds independent envSet and fileSet maps. - _ = dbgen.UserSecret(t, db, database.UserSecret{ - UserID: owner.ID, - Name: "combined", - EnvName: "GITHUB_TOKEN", - FilePath: "~/.ssh/id_rsa", - }) - - renderer := newTestRenderer(t, db, org.ID, "secret_env_and_file") - defer renderer.Close() - - out, diags := renderer.Render(ctx, owner.ID, nil, IncludeSecretRequirements()) - requireNoMissingSecret(t, diags) - require.Equal(t, []codersdk.SecretRequirementStatus{ - { - File: "~/.ssh/id_rsa", - HelpMessage: "needs file", - Satisfied: true, - }, - { - Env: "GITHUB_TOKEN", - HelpMessage: "needs env", - Satisfied: true, - }, - }, out.SecretRequirements) -} - -func TestDynamicRender_PartialEnvAndFileSatisfaction(t *testing.T) { - t.Parallel() - - db, _ := dbtestutil.NewDB(t) - ctx := t.Context() - org := dbgen.Organization(t, db, database.Organization{}) - owner := seedOwner(t, db, org.ID) - - // Env-only secret against an env+file requirement: only the file - // requirement should fail. - _ = dbgen.UserSecret(t, db, database.UserSecret{ - UserID: owner.ID, - Name: "env_only", - EnvName: "GITHUB_TOKEN", - }) - - renderer := newTestRenderer(t, db, org.ID, "secret_env_and_file") - defer renderer.Close() - - out, diags := renderer.Render(ctx, owner.ID, nil, IncludeSecretRequirements()) - requireNoMissingSecret(t, diags) - require.Equal(t, []codersdk.SecretRequirementStatus{ - { - File: "~/.ssh/id_rsa", - HelpMessage: "needs file", - Satisfied: false, - }, - { - Env: "GITHUB_TOKEN", - HelpMessage: "needs env", - Satisfied: true, - }, - }, out.SecretRequirements) -} - -func TestDynamicRender_OwnerSwitch(t *testing.T) { - t.Parallel() - - db, _ := dbtestutil.NewDB(t) - ctx := t.Context() - org := dbgen.Organization(t, db, database.Organization{}) - - // Owner A satisfies the requirement; owner B does not. - ownerA := seedOwner(t, db, org.ID) - ownerB := seedOwner(t, db, org.ID) - _ = dbgen.UserSecret(t, db, database.UserSecret{ - UserID: ownerA.ID, - Name: "gh", - EnvName: "GITHUB_TOKEN", - }) - - renderer := newTestRenderer(t, db, org.ID, "secret_required") - defer renderer.Close() - - out, diags := renderer.Render(ctx, ownerA.ID, nil, IncludeSecretRequirements()) - requireNoMissingSecret(t, diags) - require.Equal(t, []codersdk.SecretRequirementStatus{{ - Env: "GITHUB_TOKEN", - HelpMessage: "Add a GitHub PAT with env=GITHUB_TOKEN", - Satisfied: true, - }}, out.SecretRequirements) - - // The cache must not serve owner A's rows to owner B. - out, diags = renderer.Render(ctx, ownerB.ID, nil, IncludeSecretRequirements()) - requireNoMissingSecret(t, diags) - require.Equal(t, []codersdk.SecretRequirementStatus{{ - Env: "GITHUB_TOKEN", - HelpMessage: "Add a GitHub PAT with env=GITHUB_TOKEN", - Satisfied: false, - }}, out.SecretRequirements) -} - -func TestDynamicRender_DeduplicatesSecretRequirements(t *testing.T) { - t.Parallel() - - db, _ := dbtestutil.NewDB(t) - ctx := t.Context() - org := dbgen.Organization(t, db, database.Organization{}) - owner := seedOwner(t, db, org.ID) - - renderer := newTestRenderer(t, db, org.ID, "secret_required") - defer renderer.Close() - - reqs := []previewtypes.SecretRequirement{ - {Env: "GITHUB_TOKEN", HelpMessage: "z help"}, - {Env: "GITHUB_TOKEN", HelpMessage: "a help"}, - } - statuses, diags := renderer.checkSecretRequirements(ctx, owner.ID, reqs) - require.Empty(t, diags) - require.Equal(t, []codersdk.SecretRequirementStatus{{ - Env: "GITHUB_TOKEN", - HelpMessage: "a help", - Satisfied: false, - }}, statuses) -} - -// countingStore counts ListUserSecrets calls per user. -type countingStore struct { - database.Store - mu sync.Mutex - calls map[uuid.UUID]int -} - -func (c *countingStore) ListUserSecrets(ctx context.Context, userID uuid.UUID) ([]database.ListUserSecretsRow, error) { - c.mu.Lock() - if c.calls == nil { - c.calls = map[uuid.UUID]int{} - } - c.calls[userID]++ - c.mu.Unlock() - return c.Store.ListUserSecrets(ctx, userID) -} - -func (c *countingStore) callsFor(id uuid.UUID) int { - c.mu.Lock() - defer c.mu.Unlock() - return c.calls[id] -} - -// TestDynamicRender_NotAuthorizedIsCached pins that NotAuthorized -// denials hit ListUserSecrets at most once per owner. -func TestDynamicRender_NotAuthorizedIsCached(t *testing.T) { - t.Parallel() - - inner, _ := dbtestutil.NewDB(t) - db := &countingStore{Store: secretAuthDenyingStore{Store: inner}} - ctx := t.Context() - org := dbgen.Organization(t, db, database.Organization{}) - owner := seedOwner(t, db, org.ID) - - renderer := newTestRenderer(t, db, org.ID, "secret_required") - defer renderer.Close() - - for range 3 { - _, _ = renderer.Render(ctx, owner.ID, nil, IncludeSecretRequirements()) - } - require.Equal(t, 1, db.callsFor(owner.ID), - "NotAuthorized must be cached across renders") -} - -// secretAuthDenyingStore makes ListUserSecrets return NotAuthorized, -// simulating a non-owner caller. -type secretAuthDenyingStore struct { - database.Store -} - -func (secretAuthDenyingStore) ListUserSecrets(_ context.Context, _ uuid.UUID) ([]database.ListUserSecretsRow, error) { - return nil, dbauthz.NotAuthorizedError{} -} - -type secretFetchFailingStore struct { - database.Store -} - -func (secretFetchFailingStore) ListUserSecrets(_ context.Context, _ uuid.UUID) ([]database.ListUserSecretsRow, error) { - return nil, xerrors.New("fetch failed") -} - -func TestDynamicRender_SecretFetchFailedHasNilRequirements(t *testing.T) { - t.Parallel() - - inner, _ := dbtestutil.NewDB(t) - db := secretFetchFailingStore{Store: inner} - ctx := t.Context() - org := dbgen.Organization(t, db, database.Organization{}) - owner := seedOwner(t, db, org.ID) - - renderer := newTestRenderer(t, db, org.ID, "secret_required") - defer renderer.Close() - - out, diags := renderer.Render(ctx, owner.ID, nil, IncludeSecretRequirements()) - require.Nil(t, out.SecretRequirements) - requireNoMissingSecret(t, diags) - - var sawErr bool - for _, d := range diags { - extra, ok := d.Extra.(previewtypes.DiagnosticExtra) - if !ok { - continue - } - if extra.Code == DiagCodeOwnerSecretsFetchFailed { - require.Equal(t, hcl.DiagError, d.Severity) - sawErr = true - } - } - require.True(t, sawErr, "expected owner_secrets_fetch_failed error") -} - -// TestDynamicRender_NonOwnerCannotLeakSecretRequirements guards against -// a non-owner enumerating secret names via missing_secret diagnostics. -func TestDynamicRender_NonOwnerCannotLeakSecretRequirements(t *testing.T) { - t.Parallel() - - inner, _ := dbtestutil.NewDB(t) - db := secretAuthDenyingStore{Store: inner} - ctx := t.Context() - org := dbgen.Organization(t, db, database.Organization{}) - owner := seedOwner(t, db, org.ID) - - // Secret matches the requirement; a non-owner must still never - // see it. - _ = dbgen.UserSecret(t, db, database.UserSecret{ - UserID: owner.ID, - Name: "gh", - EnvName: "GITHUB_TOKEN", - }) - - renderer := newTestRenderer(t, db, org.ID, "secret_required") - defer renderer.Close() - - out, diags := renderer.Render(ctx, owner.ID, nil, IncludeSecretRequirements()) - require.Nil(t, out.SecretRequirements) - - // No missing_secret diagnostic for a non-owner, regardless of - // whether the target satisfies the requirement. - requireNoMissingSecret(t, diags) - - // Surface a warning so the admin knows validation didn't run. - var sawWarn bool - for _, d := range diags { - extra, ok := d.Extra.(previewtypes.DiagnosticExtra) - if !ok { - continue - } - if extra.Code == DiagCodeSecretValidationForbidden { - require.Equal(t, hcl.DiagWarning, d.Severity, - "secret_validation_forbidden must be a warning") - sawWarn = true - } - } - require.True(t, sawWarn, "expected secret_validation_forbidden warning") -} - -func requireNoMissingSecret(t *testing.T, diags hcl.Diagnostics) { - t.Helper() - for _, d := range diags { - if extra, ok := d.Extra.(previewtypes.DiagnosticExtra); ok && extra.Code == DiagCodeMissingSecret { - t.Fatalf("unexpected missing_secret diagnostic: %s", d.Detail) - } - } -} diff --git a/coderd/dynamicparameters/rendermock/rendermock.go b/coderd/dynamicparameters/rendermock/rendermock.go index d23c6b4705..996b02a555 100644 --- a/coderd/dynamicparameters/rendermock/rendermock.go +++ b/coderd/dynamicparameters/rendermock/rendermock.go @@ -13,7 +13,7 @@ import ( context "context" reflect "reflect" - dynamicparameters "github.com/coder/coder/v2/coderd/dynamicparameters" + preview "github.com/coder/preview" uuid "github.com/google/uuid" hcl "github.com/hashicorp/hcl/v2" gomock "go.uber.org/mock/gomock" @@ -56,21 +56,16 @@ func (mr *MockRendererMockRecorder) Close() *gomock.Call { } // Render mocks base method. -func (m *MockRenderer) Render(ctx context.Context, ownerID uuid.UUID, values map[string]string, opts ...dynamicparameters.RenderOption) (*dynamicparameters.RenderResult, hcl.Diagnostics) { +func (m *MockRenderer) Render(ctx context.Context, ownerID uuid.UUID, values map[string]string) (*preview.Output, hcl.Diagnostics) { m.ctrl.T.Helper() - varargs := []any{ctx, ownerID, values} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "Render", varargs...) - ret0, _ := ret[0].(*dynamicparameters.RenderResult) + ret := m.ctrl.Call(m, "Render", ctx, ownerID, values) + ret0, _ := ret[0].(*preview.Output) ret1, _ := ret[1].(hcl.Diagnostics) return ret0, ret1 } // Render indicates an expected call of Render. -func (mr *MockRendererMockRecorder) Render(ctx, ownerID, values any, opts ...any) *gomock.Call { +func (mr *MockRendererMockRecorder) Render(ctx, ownerID, values any) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]any{ctx, ownerID, values}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Render", reflect.TypeOf((*MockRenderer)(nil).Render), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Render", reflect.TypeOf((*MockRenderer)(nil).Render), ctx, ownerID, values) } diff --git a/coderd/dynamicparameters/resolver.go b/coderd/dynamicparameters/resolver.go index 9220685931..b0a5a027c6 100644 --- a/coderd/dynamicparameters/resolver.go +++ b/coderd/dynamicparameters/resolver.go @@ -3,7 +3,6 @@ package dynamicparameters import ( "context" "fmt" - "strings" "github.com/google/uuid" "github.com/hashicorp/hcl/v2" @@ -11,7 +10,6 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/util/slice" "github.com/coder/coder/v2/codersdk" - previewtypes "github.com/coder/preview/types" "github.com/coder/terraform-provider-coder/v2/provider" ) @@ -24,33 +22,11 @@ const ( sourcePreset ) -const ( - secretRequirementKindEnv = "env" - secretRequirementKindFile = "file" -) - type parameterValue struct { Value string Source parameterValueSource } -// ResolveOption configures optional behavior for ResolveParameters. -type ResolveOption func(*resolveOptions) - -type resolveOptions struct { - skipSecretRequirements bool -} - -// SkipSecretRequirements skips structured secret-requirement validation and -// enforcement. Callers must pass this for non-start transitions so an -// unsatisfied coder_secret, or an admin who can't read the owner's secrets, -// doesn't block stop or delete. -func SkipSecretRequirements() ResolveOption { - return func(o *resolveOptions) { - o.skipSecretRequirements = true - } -} - //nolint:revive // firstbuild is a control flag to turn on immutable validation func ResolveParameters( ctx context.Context, @@ -60,12 +36,7 @@ func ResolveParameters( previousValues []database.WorkspaceBuildParameter, buildValues []codersdk.WorkspaceBuildParameter, presetValues []database.TemplateVersionPresetParameter, - opts ...ResolveOption, ) (map[string]string, error) { - o := resolveOptions{} - for _, opt := range opts { - opt(&o) - } previousValuesMap := slice.ToMapFunc(previousValues, func(p database.WorkspaceBuildParameter) (string, string) { return p.Name, p.Value }) @@ -99,7 +70,7 @@ func ResolveParameters( // // This is how the form should look to the user on their workspace settings page. // This is the original form truth that our validations should initially be based on. - result, diags := renderer.Render(ctx, ownerID, previousValuesMap) + output, diags := renderer.Render(ctx, ownerID, previousValuesMap) if diags.HasErrors() { // Top level diagnostics should break the build. Previous values (and new) should // always be valid. If there is a case where this is not true, then this has to @@ -107,7 +78,6 @@ func ResolveParameters( return nil, parameterValidationError(diags) } - output := result.Output // The user's input now needs to be validated against the parameters. // Mutability & Ephemeral parameters depend on sequential workspace builds. @@ -128,33 +98,10 @@ func ResolveParameters( // This is the final set of values that will be used. Any errors at this stage // are fatal. Additional validation for immutability has to be done manually. - var renderOpts []RenderOption - if !o.skipSecretRequirements { - renderOpts = append(renderOpts, IncludeSecretRequirements()) - } - result, diags = renderer.Render(ctx, ownerID, values.ValuesMap(), renderOpts...) - if !o.skipSecretRequirements && !diags.HasErrors() { - var missing []codersdk.SecretRequirementStatus - for _, req := range result.SecretRequirements { - if !req.Satisfied { - missing = append(missing, req) - } - } - if len(missing) > 0 { - diags = append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Missing required secrets", - Detail: formatMissingSecrets(missing), - Extra: previewtypes.DiagnosticExtra{ - Code: DiagCodeMissingSecret, - }, - }) - } - } + output, diags = renderer.Render(ctx, ownerID, values.ValuesMap()) if diags.HasErrors() { return nil, parameterValidationError(diags) } - output = result.Output // parameterNames is going to be used to remove any excess values left // around without a parameter. @@ -281,37 +228,3 @@ func (p parameterValueMap) ValuesMap() map[string]string { } return values } - -func secretRequirementKind(env, file string) string { - switch { - case env != "" && file == "": - return secretRequirementKindEnv - case file != "" && env == "": - return secretRequirementKindFile - default: - return "" - } -} - -func formatMissingSecrets(reqs []codersdk.SecretRequirementStatus) string { - var b strings.Builder - for i, req := range reqs { - if i > 0 { - _, _ = b.WriteString("\n") - } - switch secretRequirementKind(req.Env, req.File) { - case secretRequirementKindEnv: - _, _ = fmt.Fprintf(&b, "%s %s", secretRequirementKindEnv, req.Env) - case secretRequirementKindFile: - _, _ = fmt.Fprintf(&b, "%s %s", secretRequirementKindFile, req.File) - default: - // checkSecretRequirements filters malformed requirements produced - // by preview before they reach the resolver. - _, _ = b.WriteString("malformed secret requirement") - } - if req.HelpMessage != "" { - _, _ = fmt.Fprintf(&b, ": %s", req.HelpMessage) - } - } - return b.String() -} diff --git a/coderd/dynamicparameters/resolver_internal_test.go b/coderd/dynamicparameters/resolver_internal_test.go deleted file mode 100644 index 5979f10bc0..0000000000 --- a/coderd/dynamicparameters/resolver_internal_test.go +++ /dev/null @@ -1,68 +0,0 @@ -package dynamicparameters - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/coder/coder/v2/codersdk" -) - -func TestFormatMissingSecrets(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - reqs []codersdk.SecretRequirementStatus - want string - }{ - { - name: "Env", - reqs: []codersdk.SecretRequirementStatus{{ - Env: "GITHUB_TOKEN", - HelpMessage: "Add a GitHub PAT", - }}, - want: "env GITHUB_TOKEN: Add a GitHub PAT", - }, - { - name: "File", - reqs: []codersdk.SecretRequirementStatus{{ - File: "~/.ssh/id_rsa", - }}, - want: "file ~/.ssh/id_rsa", - }, - { - name: "Multiple", - reqs: []codersdk.SecretRequirementStatus{ - { - Env: "GITHUB_TOKEN", - }, - { - File: "~/.ssh/id_rsa", - HelpMessage: "Add an SSH key", - }, - }, - want: "env GITHUB_TOKEN\nfile ~/.ssh/id_rsa: Add an SSH key", - }, - { - name: "MalformedEmpty", - reqs: []codersdk.SecretRequirementStatus{{}}, - want: "malformed secret requirement", - }, - { - name: "MalformedBothEnvAndFile", - reqs: []codersdk.SecretRequirementStatus{{ - Env: "GITHUB_TOKEN", - File: "~/.ssh/id_rsa", - }}, - want: "malformed secret requirement", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - require.Equal(t, tt.want, formatMissingSecrets(tt.reqs)) - }) - } -} diff --git a/coderd/dynamicparameters/resolver_test.go b/coderd/dynamicparameters/resolver_test.go index 0084442b62..5f2236753f 100644 --- a/coderd/dynamicparameters/resolver_test.go +++ b/coderd/dynamicparameters/resolver_test.go @@ -4,7 +4,6 @@ import ( "testing" "github.com/google/uuid" - "github.com/hashicorp/hcl/v2" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -33,37 +32,23 @@ func TestResolveParameters(t *testing.T) { render.EXPECT(). Render(gomock.Any(), gomock.Any(), gomock.Any()). AnyTimes(). - Return(renderResult( - previewtypes.Parameter{ - ParameterData: previewtypes.ParameterData{ - Name: "immutable", - Type: previewtypes.ParameterTypeString, - FormType: provider.ParameterFormTypeInput, - Mutable: false, - DefaultValue: previewtypes.StringLiteral("foo"), - Required: true, + Return(&preview.Output{ + Parameters: []previewtypes.Parameter{ + { + ParameterData: previewtypes.ParameterData{ + Name: "immutable", + Type: previewtypes.ParameterTypeString, + FormType: provider.ParameterFormTypeInput, + Mutable: false, + DefaultValue: previewtypes.StringLiteral("foo"), + Required: true, + }, + Value: previewtypes.StringLiteral("foo"), + Diagnostics: nil, }, - Value: previewtypes.StringLiteral("foo"), - Diagnostics: nil, }, - ), nil) - render.EXPECT(). - Render(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). - AnyTimes(). - Return(renderResult( - previewtypes.Parameter{ - ParameterData: previewtypes.ParameterData{ - Name: "immutable", - Type: previewtypes.ParameterTypeString, - FormType: provider.ParameterFormTypeInput, - Mutable: false, - DefaultValue: previewtypes.StringLiteral("foo"), - Required: true, - }, - Value: previewtypes.StringLiteral("foo"), - Diagnostics: nil, - }, - ), nil) + }, nil) + ctx := testutil.Context(t, testutil.WaitShort) values, err := dynamicparameters.ResolveParameters(ctx, uuid.New(), render, false, []database.WorkspaceBuildParameter{}, // No previous values @@ -96,25 +81,29 @@ func TestResolveParameters(t *testing.T) { render.EXPECT(). Render(gomock.Any(), gomock.Any(), gomock.Any()). // Return the mutable param first - Return(renderResult( - previewtypes.Parameter{ - ParameterData: mutable, - Value: previewtypes.StringLiteral("foo"), - Diagnostics: nil, + Return(&preview.Output{ + Parameters: []previewtypes.Parameter{ + { + ParameterData: mutable, + Value: previewtypes.StringLiteral("foo"), + Diagnostics: nil, + }, }, - ), nil) + }, nil) render.EXPECT(). - Render(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Render(gomock.Any(), gomock.Any(), gomock.Any()). // Then the immutable param - Return(renderResult( - previewtypes.Parameter{ - ParameterData: immutable, - // The user set the value to bar - Value: previewtypes.StringLiteral("bar"), - Diagnostics: nil, + Return(&preview.Output{ + Parameters: []previewtypes.Parameter{ + { + ParameterData: immutable, + // The user set the value to bar + Value: previewtypes.StringLiteral("bar"), + Diagnostics: nil, + }, }, - ), nil) + }, nil) ctx := testutil.Context(t, testutil.WaitShort) _, err := dynamicparameters.ResolveParameters(ctx, uuid.New(), render, false, @@ -170,39 +159,23 @@ func TestResolveParameters(t *testing.T) { render.EXPECT(). Render(gomock.Any(), gomock.Any(), gomock.Any()). AnyTimes(). - Return(renderResult( - previewtypes.Parameter{ - ParameterData: previewtypes.ParameterData{ - Name: "param", - Type: previewtypes.ParameterTypeNumber, - FormType: provider.ParameterFormTypeInput, - Mutable: true, - Validations: []*previewtypes.ParameterValidation{ - {Monotonic: ptr.Ref(tc.monotonic)}, + Return(&preview.Output{ + Parameters: []previewtypes.Parameter{ + { + ParameterData: previewtypes.ParameterData{ + Name: "param", + Type: previewtypes.ParameterTypeNumber, + FormType: provider.ParameterFormTypeInput, + Mutable: true, + Validations: []*previewtypes.ParameterValidation{ + {Monotonic: ptr.Ref(tc.monotonic)}, + }, }, + Value: previewtypes.StringLiteral(tc.cur), + Diagnostics: nil, }, - Value: previewtypes.StringLiteral(tc.cur), - Diagnostics: nil, }, - ), nil) - render.EXPECT(). - Render(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). - AnyTimes(). - Return(renderResult( - previewtypes.Parameter{ - ParameterData: previewtypes.ParameterData{ - Name: "param", - Type: previewtypes.ParameterTypeNumber, - FormType: provider.ParameterFormTypeInput, - Mutable: true, - Validations: []*previewtypes.ParameterValidation{ - {Monotonic: ptr.Ref(tc.monotonic)}, - }, - }, - Value: previewtypes.StringLiteral(tc.cur), - Diagnostics: nil, - }, - ), nil) + }, nil) var previousValues []database.WorkspaceBuildParameter if tc.prev != "" { @@ -232,172 +205,4 @@ func TestResolveParameters(t *testing.T) { }) } }) - - t.Run("BaselineRenderDoesNotRequestSecretRequirementsWhenDeactivatingRequirement", func(t *testing.T) { - t.Parallel() - - ctrl := gomock.NewController(t) - render := rendermock.NewMockRenderer(ctrl) - ownerID := uuid.New() - - gomock.InOrder( - render.EXPECT(). - Render(gomock.Any(), ownerID, map[string]string{"use_github": "true"}). - Return(renderResult(stringParameter("use_github", "true")), nil), - render.EXPECT(). - Render(gomock.Any(), ownerID, map[string]string{"use_github": "false"}, gomock.Any()). - Return(renderResult(stringParameter("use_github", "false")), nil), - ) - - ctx := testutil.Context(t, testutil.WaitShort) - values, err := dynamicparameters.ResolveParameters(ctx, ownerID, render, false, - []database.WorkspaceBuildParameter{{Name: "use_github", Value: "true"}}, - []codersdk.WorkspaceBuildParameter{{Name: "use_github", Value: "false"}}, - []database.TemplateVersionPresetParameter{}, - ) - require.NoError(t, err) - require.Equal(t, map[string]string{"use_github": "false"}, values) - }) - - t.Run("SkipSecretRequirementsAllowsFinalMissingSecrets", func(t *testing.T) { - t.Parallel() - - ctrl := gomock.NewController(t) - render := rendermock.NewMockRenderer(ctrl) - ownerID := uuid.New() - - gomock.InOrder( - render.EXPECT(). - Render(gomock.Any(), ownerID, map[string]string{"use_github": "true"}). - Return(renderResult(stringParameter("use_github", "true")), nil), - render.EXPECT(). - Render(gomock.Any(), ownerID, map[string]string{"use_github": "true"}). - Return(renderResultWithSecretRequirements( - []codersdk.SecretRequirementStatus{{ - Env: "GITHUB_TOKEN", - HelpMessage: "Add a GitHub PAT", - Satisfied: false, - }}, - stringParameter("use_github", "true"), - ), nil), - ) - - ctx := testutil.Context(t, testutil.WaitShort) - values, err := dynamicparameters.ResolveParameters(ctx, ownerID, render, false, - []database.WorkspaceBuildParameter{{Name: "use_github", Value: "true"}}, - nil, - nil, - dynamicparameters.SkipSecretRequirements(), - ) - require.NoError(t, err) - require.Equal(t, map[string]string{"use_github": "true"}, values) - }) - - t.Run("FinalMissingSecretsBlockByDefault", func(t *testing.T) { - t.Parallel() - - ctrl := gomock.NewController(t) - render := rendermock.NewMockRenderer(ctrl) - ownerID := uuid.New() - - gomock.InOrder( - render.EXPECT(). - Render(gomock.Any(), ownerID, map[string]string{"use_github": "true"}). - Return(renderResult(stringParameter("use_github", "true")), nil), - render.EXPECT(). - Render(gomock.Any(), ownerID, map[string]string{"use_github": "true"}, gomock.Any()). - Return(renderResultWithSecretRequirements( - []codersdk.SecretRequirementStatus{{ - Env: "GITHUB_TOKEN", - HelpMessage: "Add a GitHub PAT", - Satisfied: false, - }}, - stringParameter("use_github", "true"), - ), nil), - ) - - ctx := testutil.Context(t, testutil.WaitShort) - _, err := dynamicparameters.ResolveParameters(ctx, ownerID, render, false, - []database.WorkspaceBuildParameter{{Name: "use_github", Value: "true"}}, - nil, - nil, - ) - require.Error(t, err) - resp, ok := httperror.IsResponder(err) - require.True(t, ok) - _, respErr := resp.Response() - require.Contains(t, respErr.Detail, "Missing required secrets") - require.Contains(t, respErr.Detail, "env GITHUB_TOKEN: Add a GitHub PAT") - }) - - t.Run("FinalRenderErrorSuppressesMissingSecretSynthesis", func(t *testing.T) { - t.Parallel() - - ctrl := gomock.NewController(t) - render := rendermock.NewMockRenderer(ctrl) - ownerID := uuid.New() - - gomock.InOrder( - render.EXPECT(). - Render(gomock.Any(), ownerID, map[string]string{"use_github": "true"}). - Return(renderResult(stringParameter("use_github", "true")), nil), - render.EXPECT(). - Render(gomock.Any(), ownerID, map[string]string{"use_github": "true"}, gomock.Any()). - Return(renderResultWithSecretRequirements( - []codersdk.SecretRequirementStatus{{ - Env: "GITHUB_TOKEN", - HelpMessage: "Add a GitHub PAT", - Satisfied: false, - }}, - stringParameter("use_github", "true"), - ), hcl.Diagnostics{{ - Severity: hcl.DiagError, - Summary: "Render failed", - Detail: "Template parameter expression failed.", - }}), - ) - - ctx := testutil.Context(t, testutil.WaitShort) - _, err := dynamicparameters.ResolveParameters(ctx, ownerID, render, false, - []database.WorkspaceBuildParameter{{Name: "use_github", Value: "true"}}, - nil, - nil, - ) - require.Error(t, err) - resp, ok := httperror.IsResponder(err) - require.True(t, ok) - _, respErr := resp.Response() - require.Contains(t, respErr.Detail, "Render failed") - require.NotContains(t, respErr.Detail, "Missing required secrets") - }) -} - -func stringParameter(name string, value string) previewtypes.Parameter { - return previewtypes.Parameter{ - ParameterData: previewtypes.ParameterData{ - Name: name, - Type: previewtypes.ParameterTypeString, - FormType: provider.ParameterFormTypeInput, - Mutable: true, - DefaultValue: previewtypes.StringLiteral(value), - }, - Value: previewtypes.StringLiteral(value), - } -} - -func renderResult(params ...previewtypes.Parameter) *dynamicparameters.RenderResult { - return &dynamicparameters.RenderResult{ - Output: &preview.Output{ - Parameters: params, - }, - } -} - -func renderResultWithSecretRequirements(reqs []codersdk.SecretRequirementStatus, params ...previewtypes.Parameter) *dynamicparameters.RenderResult { - return &dynamicparameters.RenderResult{ - Output: &preview.Output{ - Parameters: params, - }, - SecretRequirements: reqs, - } } diff --git a/coderd/dynamicparameters/secrets.go b/coderd/dynamicparameters/secrets.go deleted file mode 100644 index 42cfcbe704..0000000000 --- a/coderd/dynamicparameters/secrets.go +++ /dev/null @@ -1,100 +0,0 @@ -package dynamicparameters - -import ( - "context" - "slices" - - "github.com/google/uuid" - "github.com/hashicorp/hcl/v2" - - "cdr.dev/slog/v3" - "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/files" - "github.com/coder/coder/v2/coderd/util/slice" - "github.com/coder/coder/v2/codersdk" - previewtypes "github.com/coder/preview/types" -) - -// EvaluateSecretMismatch reports whether the given template version -// declares coder_secret requirements that the workspace owner's secrets -// do not satisfy. Returns false (no mismatch) when the renderer cannot -// authoritatively evaluate the requirements; the reason is logged at the -// appropriate level so operators can distinguish a forbidden caller -// (expected for template admins) from a genuine renderer or DB failure. -// Returns ErrTemplateVersionNotReady when the version's provisioner job -// has not yet completed; callers should treat that as "unknown" and -// leave SecretMismatch false. -func EvaluateSecretMismatch( - ctx context.Context, - logger slog.Logger, - db database.Store, - cache files.FileAcquirer, - version database.TemplateVersion, - ownerID uuid.UUID, - buildParams []database.WorkspaceBuildParameter, -) (bool, error) { - paramValues := slice.ToMapFunc(buildParams, func(p database.WorkspaceBuildParameter) (string, string) { - return p.Name, p.Value - }) - renderer, err := Prepare(ctx, db, cache, version.ID, - WithTemplateVersion(version), - WithLogger(logger)) - if err != nil { - return false, err - } - defer renderer.Close() - - result, diags := renderer.Render(ctx, ownerID, paramValues, IncludeSecretRequirements()) - - // Three distinct "unknown" cases. Returning false from any of them - // matches the resolve-autostart handler's semantics, but they have - // very different operator implications, so we log accordingly. The - // renderer already logs its own diagnostics through the same logger, - // so we omit them here to avoid duplication. - if result.Output == nil { - logger.Warn(ctx, - "secret requirement evaluation produced no preview output; treating as unknown", - slog.F("template_version_id", version.ID), - ) - return false, nil - } - switch secretValidationBlockerCode(diags) { - case DiagCodeOwnerSecretsFetchFailed: - logger.Warn(ctx, - "failed to fetch owner secrets during requirement evaluation; treating as unknown", - slog.F("template_version_id", version.ID), - ) - return false, nil - case DiagCodeSecretValidationForbidden: - // Expected when a caller without user_secret:read on the owner - // hits the renderer, e.g. a template admin viewing another user's - // workspace. Debug-level keeps production volume sane while - // preserving visibility under trace logging. - logger.Debug(ctx, - "secret requirement evaluation forbidden for caller; treating as unknown", - slog.F("template_version_id", version.ID), - ) - return false, nil - } - - return slices.ContainsFunc(result.SecretRequirements, - func(s codersdk.SecretRequirementStatus) bool { return !s.Satisfied }), nil -} - -// secretValidationBlockerCode returns the first diagnostic code among the -// codes that indicate secret-requirement evaluation could not be -// performed. Returns the empty string if no such diagnostic is present. -// -// ExtractDiagnosticExtra walks the wrapped-extra chain so we still -// detect our marker when another extra has been chained on top by -// preview's SetDiagnosticExtra. -func secretValidationBlockerCode(diags hcl.Diagnostics) string { - for _, d := range diags { - extra := previewtypes.ExtractDiagnosticExtra(d) - switch extra.Code { - case DiagCodeOwnerSecretsFetchFailed, DiagCodeSecretValidationForbidden: - return extra.Code - } - } - return "" -} diff --git a/coderd/dynamicparameters/secrets_internal_test.go b/coderd/dynamicparameters/secrets_internal_test.go deleted file mode 100644 index cc799aca3b..0000000000 --- a/coderd/dynamicparameters/secrets_internal_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package dynamicparameters - -import ( - "testing" - - "github.com/hashicorp/hcl/v2" - "github.com/stretchr/testify/require" - - previewtypes "github.com/coder/preview/types" -) - -func TestSecretValidationBlockerCode(t *testing.T) { - t.Parallel() - - cases := []struct { - name string - in hcl.Diagnostics - want string - }{ - { - name: "Empty", - in: hcl.Diagnostics{}, - want: "", - }, - { - name: "MissingSecretIsNotBlocking", - in: hcl.Diagnostics{{ - Severity: hcl.DiagError, - Summary: "Missing required secrets", - Extra: previewtypes.DiagnosticExtra{ - Code: DiagCodeMissingSecret, - }, - }}, - want: "", - }, - { - name: "Forbidden", - in: hcl.Diagnostics{{ - Severity: hcl.DiagWarning, - Summary: "Cannot validate secret requirements", - Extra: previewtypes.DiagnosticExtra{ - Code: DiagCodeSecretValidationForbidden, - }, - }}, - want: DiagCodeSecretValidationForbidden, - }, - { - name: "FetchFailed", - in: hcl.Diagnostics{{ - Severity: hcl.DiagError, - Summary: "Failed to fetch owner secrets", - Extra: previewtypes.DiagnosticExtra{ - Code: DiagCodeOwnerSecretsFetchFailed, - }, - }}, - want: DiagCodeOwnerSecretsFetchFailed, - }, - { - name: "DiagnosticWithNoExtraIsIgnored", - in: hcl.Diagnostics{{ - Severity: hcl.DiagError, - Summary: "Some other error", - }}, - want: "", - }, - { - name: "MixedKeepsLookingUntilMatch", - in: hcl.Diagnostics{ - { - Severity: hcl.DiagError, - Summary: "Missing required secrets", - Extra: previewtypes.DiagnosticExtra{ - Code: DiagCodeMissingSecret, - }, - }, - { - Severity: hcl.DiagError, - Summary: "Failed to fetch owner secrets", - Extra: previewtypes.DiagnosticExtra{ - Code: DiagCodeOwnerSecretsFetchFailed, - }, - }, - }, - want: DiagCodeOwnerSecretsFetchFailed, - }, - { - // SetDiagnosticExtra wraps any pre-existing extra into - // previewtypes.DiagnosticExtra.Wrapped. ExtractDiagnosticExtra - // walks that chain. A naive type assertion would miss it. - name: "WrappedExtraIsDetected", - in: func() hcl.Diagnostics { - d := &hcl.Diagnostic{ - Severity: hcl.DiagWarning, - Summary: "Cannot validate secret requirements", - Extra: "some other extra", - } - previewtypes.SetDiagnosticExtra(d, previewtypes.DiagnosticExtra{ - Code: DiagCodeSecretValidationForbidden, - }) - return hcl.Diagnostics{d} - }(), - want: DiagCodeSecretValidationForbidden, - }, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - require.Equal(t, tc.want, secretValidationBlockerCode(tc.in)) - }) - } -} diff --git a/coderd/dynamicparameters/static.go b/coderd/dynamicparameters/static.go index 025d817a52..46682d3378 100644 --- a/coderd/dynamicparameters/static.go +++ b/coderd/dynamicparameters/static.go @@ -39,7 +39,7 @@ func (r *loader) staticRender(ctx context.Context, db database.Store) (*staticRe }, nil } -func (r *staticRender) Render(_ context.Context, _ uuid.UUID, values map[string]string, _ ...RenderOption) (*RenderResult, hcl.Diagnostics) { +func (r *staticRender) Render(_ context.Context, _ uuid.UUID, values map[string]string) (*preview.Output, hcl.Diagnostics) { params := r.staticParams for i := range params { param := ¶ms[i] @@ -52,10 +52,8 @@ func (r *staticRender) Render(_ context.Context, _ uuid.UUID, values map[string] param.Diagnostics = previewtypes.Diagnostics(param.Valid(param.Value)) } - return &RenderResult{ - Output: &preview.Output{ - Parameters: params, - }, + return &preview.Output{ + Parameters: params, }, hcl.Diagnostics{ { // Only a warning because the form does still work. diff --git a/coderd/dynamicparameters/testdata/secret_conditional/main.tf b/coderd/dynamicparameters/testdata/secret_conditional/main.tf deleted file mode 100644 index bcdc90ebed..0000000000 --- a/coderd/dynamicparameters/testdata/secret_conditional/main.tf +++ /dev/null @@ -1,20 +0,0 @@ -terraform { - required_providers { - coder = { - source = "coder/coder" - } - } -} - -data "coder_parameter" "use_github" { - name = "use_github" - type = "bool" - default = "false" - mutable = true -} - -data "coder_secret" "gh" { - count = data.coder_parameter.use_github.value == "true" ? 1 : 0 - env = "GITHUB_TOKEN" - help_message = "Add a GitHub PAT" -} diff --git a/coderd/dynamicparameters/testdata/secret_env_and_file/main.tf b/coderd/dynamicparameters/testdata/secret_env_and_file/main.tf deleted file mode 100644 index 24ee85ade3..0000000000 --- a/coderd/dynamicparameters/testdata/secret_env_and_file/main.tf +++ /dev/null @@ -1,17 +0,0 @@ -terraform { - required_providers { - coder = { - source = "coder/coder" - } - } -} - -data "coder_secret" "env_req" { - env = "GITHUB_TOKEN" - help_message = "needs env" -} - -data "coder_secret" "file_req" { - file = "~/.ssh/id_rsa" - help_message = "needs file" -} diff --git a/coderd/dynamicparameters/testdata/secret_required/main.tf b/coderd/dynamicparameters/testdata/secret_required/main.tf deleted file mode 100644 index 98434c5a26..0000000000 --- a/coderd/dynamicparameters/testdata/secret_required/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -terraform { - required_providers { - coder = { - source = "coder/coder" - } - } -} - -data "coder_secret" "gh" { - env = "GITHUB_TOKEN" - help_message = "Add a GitHub PAT with env=GITHUB_TOKEN" -} diff --git a/coderd/parameters.go b/coderd/parameters.go index 2531655651..730fac6044 100644 --- a/coderd/parameters.go +++ b/coderd/parameters.go @@ -8,23 +8,16 @@ import ( "github.com/google/uuid" "golang.org/x/xerrors" - "cdr.dev/slog/v3" "github.com/coder/coder/v2/coderd/database/db2sdk" - "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/dynamicparameters" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" - "github.com/coder/coder/v2/coderd/rbac" - "github.com/coder/coder/v2/coderd/rbac/policy" - "github.com/coder/coder/v2/coderd/usersecretspubsub" "github.com/coder/coder/v2/coderd/util/slice" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/wsjson" "github.com/coder/websocket" ) -const initialDynamicParametersResponseID = -1 - // @Summary Evaluate dynamic parameters for template version // @ID evaluate-dynamic-parameters-for-template-version // @Security CoderSessionToken @@ -70,7 +63,7 @@ func (api *API) templateVersionDynamicParametersWebsocket(rw http.ResponseWriter } api.templateVersionDynamicParameters(true, codersdk.DynamicParametersRequest{ - ID: initialDynamicParametersResponseID, + ID: -1, Inputs: map[string]string{}, OwnerID: userID, })(rw, r) @@ -89,7 +82,6 @@ func (api *API) templateVersionDynamicParameters(listen bool, initial codersdk.D renderer, err := dynamicparameters.Prepare(ctx, api.Database, api.FileCache, templateVersion.ID, dynamicparameters.WithTemplateVersion(templateVersion), - dynamicparameters.WithLogger(api.Logger.Named("dynamicparameters")), ) if err != nil { if httpapi.Is404Error(err) { @@ -124,7 +116,15 @@ func (*API) handleParameterEvaluate(rw http.ResponseWriter, r *http.Request, ini ctx := r.Context() // Send an initial form state, computed without any user input. - response := renderDynamicParametersResponse(ctx, render, 0, initial.OwnerID, initial.Inputs) + result, diagnostics := render.Render(ctx, initial.OwnerID, initial.Inputs) + response := codersdk.DynamicParametersResponse{ + ID: 0, + Diagnostics: db2sdk.HCLDiagnostics(diagnostics), + } + if result != nil { + response.Parameters = slice.List(result.Parameters, db2sdk.PreviewParameter) + } + httpapi.Write(ctx, rw, http.StatusOK, response) } @@ -149,43 +149,30 @@ func (api *API) handleParameterWebsocket(rw http.ResponseWriter, r *http.Request api.Logger, ) - secretEvents := make(chan uuid.UUID, 1) - secretSubscriber := ¶meterSecretEventSubscriber{ - api: api, - events: secretEvents, - } - secretSubscriber.UpdateOwnerSubscription(ctx, initial.OwnerID) - defer secretSubscriber.Close() - - sender := dynamicParametersResponseSender{ - stream: stream, - render: render, - } - // Send an initial form state, computed without any user input. - if !sender.Send(ctx, initialDynamicParametersResponseID, initial.OwnerID, initial.Inputs) { + result, diagnostics := render.Render(ctx, initial.OwnerID, initial.Inputs) + response := codersdk.DynamicParametersResponse{ + ID: -1, // Always start with -1. + Diagnostics: db2sdk.HCLDiagnostics(diagnostics), + } + if result != nil { + response.Parameters = slice.List(result.Parameters, db2sdk.PreviewParameter) + } + err = stream.Send(response) + if err != nil { + stream.Drop() return } - // As the user types into the form or updates secrets in another client, - // reprocess the state using their input and respond with updates. + // As the user types into the form, reprocess the state using their input, + // and respond with updates. updates := stream.Chan() ownerID := initial.OwnerID - inputs := initial.Inputs - lastResponseID := initialDynamicParametersResponseID for { select { case <-ctx.Done(): stream.Close(websocket.StatusGoingAway) return - case eventOwnerID := <-secretEvents: - if eventOwnerID != ownerID { - continue - } - lastResponseID = nextDynamicParametersResponseID(lastResponseID, lastResponseID+1) - if !sender.Send(ctx, lastResponseID, ownerID, inputs) { - return - } case update, ok := <-updates: if !ok { // The connection has been closed, so there is no one to write to @@ -199,130 +186,20 @@ func (api *API) handleParameterWebsocket(rw http.ResponseWriter, r *http.Request } ownerID = update.OwnerID - inputs = update.Inputs - secretSubscriber.UpdateOwnerSubscription(ctx, ownerID) - responseID := nextDynamicParametersResponseID(lastResponseID, update.ID) - lastResponseID = responseID - if !sender.Send(ctx, responseID, ownerID, inputs) { + + result, diagnostics := render.Render(ctx, update.OwnerID, update.Inputs) + response := codersdk.DynamicParametersResponse{ + ID: update.ID, + Diagnostics: db2sdk.HCLDiagnostics(diagnostics), + } + if result != nil { + response.Parameters = slice.List(result.Parameters, db2sdk.PreviewParameter) + } + err = stream.Send(response) + if err != nil { + stream.Drop() return } } } } - -func renderDynamicParametersResponse( - ctx context.Context, - render dynamicparameters.Renderer, - id int, - ownerID uuid.UUID, - inputs map[string]string, -) codersdk.DynamicParametersResponse { - result, diagnostics := render.Render(ctx, ownerID, inputs, dynamicparameters.IncludeSecretRequirements()) - response := codersdk.DynamicParametersResponse{ - ID: id, - Diagnostics: db2sdk.HCLDiagnostics(diagnostics), - } - if result.Output != nil { - response.Parameters = slice.List(result.Output.Parameters, db2sdk.PreviewParameter) - } - response.SecretRequirements = result.SecretRequirements - return response -} - -type dynamicParametersResponseSender struct { - stream *wsjson.Stream[codersdk.DynamicParametersRequest, codersdk.DynamicParametersResponse] - render dynamicparameters.Renderer -} - -func (s dynamicParametersResponseSender) Send( - ctx context.Context, - id int, - ownerID uuid.UUID, - inputs map[string]string, -) bool { - response := renderDynamicParametersResponse(ctx, s.render, id, ownerID, inputs) - if err := s.stream.Send(response); err != nil { - s.stream.Drop() - return false - } - return true -} - -type parameterSecretEventSubscriber struct { - api *API - events chan uuid.UUID - - cancel func() - ownerID uuid.UUID -} - -// UpdateOwnerSubscription switches the pubsub subscription to the owner's -// user secret channel. Dynamic parameters can render for a workspace owner -// other than the connected user, so owner changes must update the channel -// that drives secret requirement refreshes. -func (s *parameterSecretEventSubscriber) UpdateOwnerSubscription(ctx context.Context, ownerID uuid.UUID) { - if ownerID == s.ownerID { - return - } - if s.cancel != nil { - s.Close() - } - // Websocket authorization uses the actor snapshot from connection - // creation, matching the rest of the websocket handlers. - if !s.api.canSubscribeUserSecretEvents(ctx, ownerID) { - s.ownerID = ownerID - return - } - s.ownerID = ownerID - subscribedOwnerID := ownerID - cancel, err := s.api.Pubsub.Subscribe(usersecretspubsub.Channel(ownerID), func(context.Context, []byte) { - s.notify(subscribedOwnerID) - }) - if err != nil { - // Leave the owner unset so transient pubsub failures can be - // retried on the next update for this owner. - s.ownerID = uuid.Nil - s.api.Logger.Warn(ctx, "failed to subscribe to user secret events", - slog.F("user_id", ownerID), - slog.Error(err), - ) - return - } - s.cancel = cancel -} - -func (s *parameterSecretEventSubscriber) Close() { - if s.cancel == nil { - return - } - s.cancel() - s.cancel = nil -} - -func (s *parameterSecretEventSubscriber) notify(ownerID uuid.UUID) { - select { - case s.events <- ownerID: - default: - } -} - -func nextDynamicParametersResponseID(lastResponseID int, requestID int) int { - if requestID <= lastResponseID { - return lastResponseID + 1 - } - return requestID -} - -func (api *API) canSubscribeUserSecretEvents(ctx context.Context, ownerID uuid.UUID) bool { - roles, ok := dbauthz.ActorFromContext(ctx) - if !ok { - api.Logger.Error(ctx, "no authorization actor for user secret event subscription") - return false - } - return api.HTTPAuth.Authorizer.Authorize( - ctx, - roles, - policy.ActionRead, - rbac.ResourceUserSecret.WithOwner(ownerID.String()), - ) == nil -} diff --git a/coderd/parameters_internal_test.go b/coderd/parameters_internal_test.go deleted file mode 100644 index 4b08064ffd..0000000000 --- a/coderd/parameters_internal_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package coderd - -import ( - "context" - "testing" - - "github.com/google/uuid" - "github.com/stretchr/testify/require" - "golang.org/x/xerrors" - - "cdr.dev/slog/v3" - "cdr.dev/slog/v3/sloggers/slogtest" - "github.com/coder/coder/v2/coderd/database/dbauthz" - "github.com/coder/coder/v2/coderd/rbac" - "github.com/coder/coder/v2/coderd/rbac/policy" - "github.com/coder/coder/v2/testutil" -) - -func TestNextDynamicParametersResponseID(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - lastResponseID int - requestID int - want int - }{ - { - name: "request ID advances response ID", - lastResponseID: 1, - requestID: 4, - want: 4, - }, - { - name: "request ID collision advances response ID", - lastResponseID: 4, - requestID: 4, - want: 5, - }, - { - name: "stale request ID advances response ID", - lastResponseID: 4, - requestID: 2, - want: 5, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - - got := nextDynamicParametersResponseID(tt.lastResponseID, tt.requestID) - require.Equal(t, tt.want, got) - }) - } -} - -func TestCanSubscribeUserSecretEventsRequiresSecretRead(t *testing.T) { - t.Parallel() - - ownerID := uuid.New() - actor := rbac.Subject{ID: uuid.NewString()} - - t.Run("allowed", func(t *testing.T) { - t.Parallel() - - auth := &recordingAuthorizer{} - api := &API{ - Options: &Options{ - Logger: testutil.Logger(t), - }, - HTTPAuth: &HTTPAuthorizer{ - Authorizer: auth, - Logger: testutil.Logger(t), - }, - } - ctx := dbauthz.As(t.Context(), actor) //nolint:gocritic // Testing authorization from the request context. - - require.True(t, api.canSubscribeUserSecretEvents(ctx, ownerID)) - require.Len(t, auth.calls, 1) - require.Equal(t, actor, auth.calls[0].Actor) - require.Equal(t, policy.ActionRead, auth.calls[0].Action) - require.Equal(t, rbac.ResourceUserSecret.Type, auth.calls[0].Object.Type) - require.Equal(t, ownerID.String(), auth.calls[0].Object.Owner) - }) - - t.Run("denied", func(t *testing.T) { - t.Parallel() - - auth := &recordingAuthorizer{err: xerrors.New("denied")} - api := &API{ - Options: &Options{ - Logger: testutil.Logger(t), - }, - HTTPAuth: &HTTPAuthorizer{ - Authorizer: auth, - Logger: testutil.Logger(t), - }, - } - ctx := dbauthz.As(t.Context(), actor) //nolint:gocritic // Testing authorization from the request context. - - require.False(t, api.canSubscribeUserSecretEvents(ctx, ownerID)) - require.Len(t, auth.calls, 1) - }) - - t.Run("no actor", func(t *testing.T) { - t.Parallel() - - auth := &recordingAuthorizer{} - logger := slogtest.Make(t, &slogtest.Options{ - IgnoredErrorIs: []error{}, - IgnoreErrorFn: func(entry slog.SinkEntry) bool { - return entry.Message == "no authorization actor for user secret event subscription" - }, - }) - api := &API{ - Options: &Options{ - Logger: logger, - }, - HTTPAuth: &HTTPAuthorizer{ - Authorizer: auth, - Logger: logger, - }, - } - - require.False(t, api.canSubscribeUserSecretEvents(context.Background(), ownerID)) - require.Empty(t, auth.calls) - }) -} - -type recordingAuthorizer struct { - err error - calls []rbac.AuthCall -} - -func (a *recordingAuthorizer) Authorize(_ context.Context, subject rbac.Subject, action policy.Action, object rbac.Object) error { - a.calls = append(a.calls, rbac.AuthCall{ - Actor: subject, - Action: action, - Object: object, - }) - return a.err -} - -func (*recordingAuthorizer) Prepare(context.Context, rbac.Subject, policy.Action, string) (rbac.PreparedAuthorized, error) { - //nolint:nilnil // Prepare is unused by these tests. - return nil, nil -} diff --git a/coderd/parameters_test.go b/coderd/parameters_test.go index a41af06dbb..1229a61dc9 100644 --- a/coderd/parameters_test.go +++ b/coderd/parameters_test.go @@ -16,7 +16,6 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/pubsub" - "github.com/coder/coder/v2/coderd/dynamicparameters" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/wsjson" @@ -387,433 +386,11 @@ func TestDynamicParametersWithTerraformValues(t *testing.T) { coderdtest.AssertParameter(t, "variable_values", preview.Parameters). Exists().Value("austin") }) - - t.Run("MissingSecret", func(t *testing.T) { - t.Parallel() - - dynamicParametersTerraformSource, err := os.ReadFile("testdata/parameters/secret_required/main.tf") - require.NoError(t, err) - - setup := setupDynamicParamsTest(t, setupDynamicParamsTestParams{ - provisionerDaemonVersion: provProto.CurrentVersion.String(), - mainTF: dynamicParametersTerraformSource, - }) - - ctx := testutil.Context(t, testutil.WaitShort) - previews := setup.stream.Chan() - - preview := testutil.RequireReceive(ctx, t, previews) - require.Equal(t, -1, preview.ID) - for _, diag := range preview.Diagnostics { - require.NotEqual(t, dynamicparameters.DiagCodeMissingSecret, diag.Extra.Code) - } - require.Equal(t, []codersdk.SecretRequirementStatus{{ - Env: "GITHUB_TOKEN", - HelpMessage: "Add a GitHub PAT with env=GITHUB_TOKEN", - Satisfied: false, - }}, preview.SecretRequirements) - }) - - t.Run("SecretRequirementPushesOnSecretChange", func(t *testing.T) { - t.Parallel() - - dynamicParametersTerraformSource, err := os.ReadFile("testdata/parameters/secret_required/main.tf") - require.NoError(t, err) - - setup := setupDynamicParamsTest(t, setupDynamicParamsTestParams{ - provisionerDaemonVersion: provProto.CurrentVersion.String(), - mainTF: dynamicParametersTerraformSource, - }) - - ctx := testutil.Context(t, testutil.WaitMedium) - previews := setup.stream.Chan() - - preview := testutil.RequireReceive(ctx, t, previews) - require.Equal(t, -1, preview.ID) - require.Len(t, preview.SecretRequirements, 1) - require.False(t, preview.SecretRequirements[0].Satisfied) - - _, err = setup.dynamicParamsClient.CreateUserSecret(ctx, codersdk.Me, codersdk.CreateUserSecretRequest{ - Name: "github-token", - Value: "ghp_test", - EnvName: "GITHUB_TOKEN", - }) - require.NoError(t, err) - - preview = testutil.RequireReceive(ctx, t, previews) - require.Equal(t, 0, preview.ID) - require.Len(t, preview.SecretRequirements, 1) - require.True(t, preview.SecretRequirements[0].Satisfied) - - err = setup.dynamicParamsClient.DeleteUserSecret(ctx, codersdk.Me, "github-token") - require.NoError(t, err) - - preview = testutil.RequireReceive(ctx, t, previews) - require.Equal(t, 1, preview.ID) - require.Len(t, preview.SecretRequirements, 1) - require.False(t, preview.SecretRequirements[0].Satisfied) - - _, err = setup.dynamicParamsClient.CreateUserSecret(ctx, codersdk.Me, codersdk.CreateUserSecretRequest{ - Name: "github-token", - Value: "ghp_test", - EnvName: "GITHUB_TOKEN", - }) - require.NoError(t, err) - - preview = testutil.RequireReceive(ctx, t, previews) - require.Equal(t, 2, preview.ID) - require.Len(t, preview.SecretRequirements, 1) - require.True(t, preview.SecretRequirements[0].Satisfied) - - otherEnvName := "OTHER_GITHUB_TOKEN" - _, err = setup.dynamicParamsClient.UpdateUserSecret(ctx, codersdk.Me, "github-token", codersdk.UpdateUserSecretRequest{ - EnvName: &otherEnvName, - }) - require.NoError(t, err) - - preview = testutil.RequireReceive(ctx, t, previews) - require.Equal(t, 3, preview.ID) - require.Len(t, preview.SecretRequirements, 1) - require.False(t, preview.SecretRequirements[0].Satisfied) - }) - - t.Run("SecretRequirementPushesAfterOwnerSwitch", func(t *testing.T) { - t.Parallel() - - dynamicParametersTerraformSource, err := os.ReadFile("testdata/parameters/secret_required/main.tf") - require.NoError(t, err) - - setup := setupDynamicParamsTest(t, setupDynamicParamsTestParams{ - // No production role grants cross-user user_secret:read today, - // so use an allow-all authorizer for lifecycle coverage. - authorizer: &coderdtest.FakeAuthorizer{}, - provisionerDaemonVersion: provProto.CurrentVersion.String(), - mainTF: dynamicParametersTerraformSource, - }) - - ctx := testutil.Context(t, testutil.WaitMedium) - previews := setup.stream.Chan() - targetClient, target := coderdtest.CreateAnotherUser(t, setup.client, setup.template.OrganizationID) - - preview := testutil.RequireReceive(ctx, t, previews) - require.Equal(t, -1, preview.ID) - require.Len(t, preview.SecretRequirements, 1) - require.False(t, preview.SecretRequirements[0].Satisfied) - - err = setup.stream.Send(codersdk.DynamicParametersRequest{ - ID: 0, - Inputs: map[string]string{}, - OwnerID: target.ID, - }) - require.NoError(t, err) - - preview = testutil.RequireReceive(ctx, t, previews) - require.Equal(t, 0, preview.ID) - require.Len(t, preview.SecretRequirements, 1) - require.False(t, preview.SecretRequirements[0].Satisfied) - - _, err = targetClient.CreateUserSecret(ctx, codersdk.Me, codersdk.CreateUserSecretRequest{ - Name: "github-token", - Value: "ghp_target", - EnvName: "GITHUB_TOKEN", - }) - require.NoError(t, err) - - preview = testutil.RequireReceive(ctx, t, previews) - require.Equal(t, 1, preview.ID) - require.Len(t, preview.SecretRequirements, 1) - require.True(t, preview.SecretRequirements[0].Satisfied) - - _, err = setup.dynamicParamsClient.CreateUserSecret(ctx, codersdk.Me, codersdk.CreateUserSecretRequest{ - Name: "github-token", - Value: "ghp_initial", - EnvName: "GITHUB_TOKEN", - }) - require.NoError(t, err) - - require.Never(t, func() bool { - select { - case <-previews: - return true - default: - return false - } - }, testutil.WaitShort/5, testutil.IntervalFast) - }) - - t.Run("SecretRequirementDoesNotSubscribeWhenOwnerUnauthorized", func(t *testing.T) { - t.Parallel() - - dynamicParametersTerraformSource, err := os.ReadFile("testdata/parameters/secret_required/main.tf") - require.NoError(t, err) - - setup := setupDynamicParamsTest(t, setupDynamicParamsTestParams{ - provisionerDaemonVersion: provProto.CurrentVersion.String(), - mainTF: dynamicParametersTerraformSource, - }) - - ctx := testutil.Context(t, testutil.WaitMedium) - previews := setup.stream.Chan() - targetClient, target := coderdtest.CreateAnotherUser(t, setup.client, setup.template.OrganizationID) - - preview := testutil.RequireReceive(ctx, t, previews) - require.Equal(t, -1, preview.ID) - require.Len(t, preview.SecretRequirements, 1) - require.False(t, preview.SecretRequirements[0].Satisfied) - - err = setup.stream.Send(codersdk.DynamicParametersRequest{ - ID: 0, - Inputs: map[string]string{}, - OwnerID: target.ID, - }) - require.NoError(t, err) - - preview = testutil.RequireReceive(ctx, t, previews) - require.Equal(t, 0, preview.ID) - require.Empty(t, preview.SecretRequirements) - require.Len(t, preview.Diagnostics, 1) - require.Equal(t, dynamicparameters.DiagCodeSecretValidationForbidden, preview.Diagnostics[0].Extra.Code) - - _, err = targetClient.CreateUserSecret(ctx, codersdk.Me, codersdk.CreateUserSecretRequest{ - Name: "github-token", - Value: "ghp_target", - EnvName: "GITHUB_TOKEN", - }) - require.NoError(t, err) - - require.Never(t, func() bool { - select { - case <-previews: - return true - default: - return false - } - }, testutil.WaitShort/5, testutil.IntervalFast) - }) - - // Regression test for PLAT-100: a workspace whose template has an - // unsatisfied coder_secret requirement must still be stoppable and - // deletable. Start remains blocked. - t.Run("SecretRequirementDoesNotBlockStopOrDelete", func(t *testing.T) { - t.Parallel() - - dynamicParametersTerraformSource, err := os.ReadFile("testdata/parameters/secret_required/main.tf") - require.NoError(t, err) - - setup := setupDynamicParamsTest(t, setupDynamicParamsTestParams{ - provisionerDaemonVersion: provProto.CurrentVersion.String(), - mainTF: dynamicParametersTerraformSource, - }) - _ = setup.stream.Close(websocket.StatusGoingAway) - - ctx := testutil.Context(t, testutil.WaitLong) - - // Owner must satisfy the coder_secret requirement to create - // the workspace; delete it later to provoke the bug scenario. - _, err = setup.client.CreateUserSecret(ctx, codersdk.Me, codersdk.CreateUserSecretRequest{ - Name: "github-token", - Value: "ghp_test", - EnvName: "GITHUB_TOKEN", - }) - require.NoError(t, err) - - wrk := coderdtest.CreateWorkspace(t, setup.client, setup.template.ID) - coderdtest.AwaitWorkspaceBuildJobCompleted(t, setup.client, wrk.LatestBuild.ID) - - require.NoError(t, setup.client.DeleteUserSecret(ctx, codersdk.Me, "github-token")) - - // Start on the now-unsatisfied requirement must still fail; - // otherwise we've over-filtered the diagnostic. - _, err = setup.client.CreateWorkspaceBuild(ctx, wrk.ID, codersdk.CreateWorkspaceBuildRequest{ - Transition: codersdk.WorkspaceTransitionStart, - }) - require.Error(t, err, "start must still reject unsatisfied secret requirement") - var sdkErr *codersdk.Error - require.ErrorAs(t, err, &sdkErr) - require.Contains(t, sdkErr.Detail, "Missing required secrets") - require.Contains(t, sdkErr.Detail, "env GITHUB_TOKEN") - - // Stop must succeed despite the unsatisfied requirement. - stop, err := setup.client.CreateWorkspaceBuild(ctx, wrk.ID, codersdk.CreateWorkspaceBuildRequest{ - Transition: codersdk.WorkspaceTransitionStop, - }) - require.NoError(t, err) - coderdtest.AwaitWorkspaceBuildJobCompleted(t, setup.client, stop.ID) - - // Delete must succeed despite the unsatisfied requirement. - del, err := setup.client.CreateWorkspaceBuild(ctx, wrk.ID, codersdk.CreateWorkspaceBuildRequest{ - Transition: codersdk.WorkspaceTransitionDelete, - }) - require.NoError(t, err) - coderdtest.AwaitWorkspaceBuildJobCompleted(t, setup.client, del.ID) - }) -} - -// TestResolveAutostartPreservesParameterMismatchOnSecretEvalError exercises -// the handler's default switch arm: when EvaluateSecretMismatch returns a -// non-ErrTemplateVersionNotReady error, the handler must log and treat -// SecretMismatch as "unknown" without dropping the already-computed -// ParameterMismatch signal. -func TestResolveAutostartPreservesParameterMismatchOnSecretEvalError(t *testing.T) { - t.Parallel() - - db, ps := dbtestutil.NewDB(t) - - // Wrap the DB so we can fail the renderer's GetTemplateVersionTerraformValues - // call. Toggle is flipped on after setup so initial template version - // processing succeeds. - reject := &dbRejectTemplateVersionTerraformValues{Store: db} - - noRequirementsTF := []byte(`terraform { - required_providers { - coder = { - source = "coder/coder" - } - } -} -`) - setup := setupDynamicParamsTest(t, setupDynamicParamsTestParams{ - db: reject, - ps: ps, - provisionerDaemonVersion: provProto.CurrentVersion.String(), - mainTF: noRequirementsTF, - }) - _ = setup.stream.Close(websocket.StatusGoingAway) - - wrk := coderdtest.CreateWorkspace(t, setup.client, setup.template.ID, - func(req *codersdk.CreateWorkspaceRequest) { - req.AutomaticUpdates = codersdk.AutomaticUpdatesAlways - }) - coderdtest.AwaitWorkspaceBuildJobCompleted(t, setup.client, wrk.LatestBuild.ID) - - // Push a v2 that adds a required-no-default parameter so resolve-autostart - // computes ParameterMismatch=true. The new version becomes active via - // DynamicParameterTemplate's UpdateActiveTemplateVersion call. - paramRequiredTF := []byte(`terraform { - required_providers { - coder = { - source = "coder/coder" - } - } -} - -data "coder_parameter" "required_param" { - name = "required_param" - type = "string" -} -`) - // StaticParams populates the legacy template_version_parameters table via - // the GraphComplete response. resolve-autostart reads from this table to - // determine ParameterMismatch. - _, _ = coderdtest.DynamicParameterTemplate(t, setup.dynamicParamsClient, - wrk.OrganizationID, - coderdtest.DynamicParameterTemplateParams{ - MainTF: string(paramRequiredTF), - TemplateID: setup.template.ID, - StaticParams: []*proto.RichParameter{{ - Name: "required_param", - Type: "string", - Required: true, - }}, - }) - - // Arm the rejection only for the resolve-autostart call. Setup has - // already completed, so all earlier calls passed through. - reject.SetReject(true) - - ctx := testutil.Context(t, testutil.WaitLong) - resp, err := setup.client.ResolveAutostart(ctx, wrk.ID.String()) - require.NoError(t, err, "resolve-autostart must not 500 when secret evaluation fails") - require.True(t, resp.ParameterMismatch, "ParameterMismatch should be preserved across secret evaluation failure") - require.False(t, resp.SecretMismatch, "SecretMismatch should be unknown (false) when evaluation fails") -} - -// TestResolveAutostartSecretRequirements is the PLAT-81 backend coverage: -// resolve-autostart must surface coder_secret requirements declared by the -// active template version that the workspace owner's secrets do not -// satisfy. The dashboard banner uses this to tell the user autostart -// cannot run the auto-update build until they create the missing secrets. -func TestResolveAutostartSecretRequirements(t *testing.T) { - t.Parallel() - - noRequirementsTF := []byte(`terraform { - required_providers { - coder = { - source = "coder/coder" - } - } -} -`) - secretRequiredTF, err := os.ReadFile("testdata/parameters/secret_required/main.tf") - require.NoError(t, err) - - // v1 has no secret requirements; we need a workspace to exist so - // resolve-autostart enters its version-mismatch branch. - setup := setupDynamicParamsTest(t, setupDynamicParamsTestParams{ - provisionerDaemonVersion: provProto.CurrentVersion.String(), - mainTF: noRequirementsTF, - }) - _ = setup.stream.Close(websocket.StatusGoingAway) - - wrk := coderdtest.CreateWorkspace(t, setup.client, setup.template.ID, - func(req *codersdk.CreateWorkspaceRequest) { - req.AutomaticUpdates = codersdk.AutomaticUpdatesAlways - }) - coderdtest.AwaitWorkspaceBuildJobCompleted(t, setup.client, wrk.LatestBuild.ID) - - // Push v2 with a coder_secret requirement and make it active. - _, _ = coderdtest.DynamicParameterTemplate(t, setup.dynamicParamsClient, - wrk.OrganizationID, - coderdtest.DynamicParameterTemplateParams{ - MainTF: string(secretRequiredTF), - TemplateID: setup.template.ID, - }) - - t.Run("OwnerSeesMismatchThenSatisfies", func(t *testing.T) { - t.Parallel() - ctx := testutil.Context(t, testutil.WaitLong) - - // Owner has no GITHUB_TOKEN secret; resolve-autostart must surface - // the unsatisfied requirement. - resp, err := setup.client.ResolveAutostart(ctx, wrk.ID.String()) - require.NoError(t, err) - require.False(t, resp.ParameterMismatch) - require.True(t, resp.SecretMismatch) - - // Creating the matching secret must clear the entry without further - // template changes. - _, err = setup.client.CreateUserSecret(ctx, codersdk.Me, codersdk.CreateUserSecretRequest{ - Name: "github-token", - Value: "ghp_test", - EnvName: "GITHUB_TOKEN", - }) - require.NoError(t, err) - - resp, err = setup.client.ResolveAutostart(ctx, wrk.ID.String()) - require.NoError(t, err) - require.False(t, resp.ParameterMismatch) - require.False(t, resp.SecretMismatch) - }) - - t.Run("ForbiddenCallerSeesNoMismatch", func(t *testing.T) { - t.Parallel() - ctx := testutil.Context(t, testutil.WaitLong) - - // The template-admin client can read the workspace but lacks - // user_secret:read on the workspace owner. The renderer's secret - // fetch produces a forbidden diagnostic, and the handler must - // treat that as "unknown" and report SecretMismatch=false rather - // than leaking a 500 or a stale true value. - resp, err := setup.dynamicParamsClient.ResolveAutostart(ctx, wrk.ID.String()) - require.NoError(t, err) - require.False(t, resp.SecretMismatch) - }) } type setupDynamicParamsTestParams struct { db database.Store ps pubsub.Pubsub - authorizer rbac.Authorizer provisionerDaemonVersion string mainTF []byte modulesArchive []byte @@ -825,18 +402,16 @@ type setupDynamicParamsTestParams struct { } type dynamicParamsTest struct { - client *codersdk.Client - dynamicParamsClient *codersdk.Client - api *coderd.API - stream *wsjson.Stream[codersdk.DynamicParametersResponse, codersdk.DynamicParametersRequest] - template codersdk.Template + client *codersdk.Client + api *coderd.API + stream *wsjson.Stream[codersdk.DynamicParametersResponse, codersdk.DynamicParametersRequest] + template codersdk.Template } func setupDynamicParamsTest(t *testing.T, args setupDynamicParamsTestParams) dynamicParamsTest { ownerClient, _, api := coderdtest.NewWithAPI(t, &coderdtest.Options{ Database: args.db, Pubsub: args.ps, - Authorizer: args.authorizer, IncludeProvisionerDaemon: true, ProvisionerDaemonVersion: args.provisionerDaemonVersion, }) @@ -871,11 +446,10 @@ func setupDynamicParamsTest(t *testing.T, args setupDynamicParamsTestParams) dyn }) return dynamicParamsTest{ - client: ownerClient, - dynamicParamsClient: templateAdmin, - api: api, - stream: stream, - template: tpl, + client: ownerClient, + api: api, + stream: stream, + template: tpl, } } @@ -910,34 +484,3 @@ func (d *dbRejectGitSSHKey) GetGitSSHKey(ctx context.Context, userID uuid.UUID) return d.Store.GetGitSSHKey(ctx, userID) } - -// dbRejectTemplateVersionTerraformValues wraps a Store so the dynamic -// parameter renderer's GetTemplateVersionTerraformValues call can be made -// to fail on demand. This forces the resolve-autostart handler into the -// default switch arm where EvaluateSecretMismatch returns a non- -// ErrTemplateVersionNotReady error. -type dbRejectTemplateVersionTerraformValues struct { - database.Store - rejectMu sync.RWMutex - reject bool -} - -// SetReject toggles whether GetTemplateVersionTerraformValues should -// return an error or passthrough to the underlying store. -func (d *dbRejectTemplateVersionTerraformValues) SetReject(reject bool) { - d.rejectMu.Lock() - defer d.rejectMu.Unlock() - d.reject = reject -} - -func (d *dbRejectTemplateVersionTerraformValues) GetTemplateVersionTerraformValues(ctx context.Context, templateVersionID uuid.UUID) (database.TemplateVersionTerraformValue, error) { - d.rejectMu.RLock() - reject := d.reject - d.rejectMu.RUnlock() - - if reject { - return database.TemplateVersionTerraformValue{}, xerrors.New("forcing a fake error") - } - - return d.Store.GetTemplateVersionTerraformValues(ctx, templateVersionID) -} diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index 2fd3c50671..5a52ecc0a1 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -591,26 +591,6 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo } } - // Fetch user secrets for build-time injection, but only on start - // transitions where the workspace actually needs them. - var userSecrets []*sdkproto.UserSecretValue - if workspaceBuild.Transition == database.WorkspaceTransitionStart { - dbSecrets, err := s.Database.ListUserSecretsWithValues(ctx, owner.ID) - if err != nil { - return nil, failJob(fmt.Sprintf("get user secrets: %s", err)) - } - for _, secret := range dbSecrets { - if secret.EnvName == "" && secret.FilePath == "" { - continue - } - userSecrets = append(userSecrets, &sdkproto.UserSecretValue{ - EnvName: secret.EnvName, - FilePath: secret.FilePath, - Value: []byte(secret.Value), - }) - } - } - transition, err := convertWorkspaceTransition(workspaceBuild.Transition) if err != nil { return nil, failJob(fmt.Sprintf("convert workspace transition: %s", err)) @@ -793,8 +773,7 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo TaskPrompt: task.Prompt, TemplateVersionModulesFile: versionModulesFile, }, - LogLevel: input.LogLevel, - UserSecrets: userSecrets, + LogLevel: input.LogLevel, }, } case database.ProvisionerJobTypeTemplateVersionDryRun: diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index 2f3e644241..007c26cb18 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -856,368 +856,6 @@ func TestAcquireJob(t *testing.T) { require.NoError(t, err) require.JSONEq(t, string(want), string(got)) }) - t.Run(tc.name+"_UserSecrets", func(t *testing.T) { - t.Parallel() - srv, db, ps, pd := setup(t, false, nil) - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) - defer cancel() - - user := dbgen.User(t, db, database.User{}) - dbgen.OrganizationMember(t, db, database.OrganizationMember{ - UserID: user.ID, - OrganizationID: pd.OrganizationID, - }) - dbgen.GitSSHKey(t, db, database.GitSSHKey{UserID: user.ID}) - - // Create secrets: 4 valid + 1 that should be filtered out. - insert1 := database.UserSecret{ID: uuid.New(), UserID: user.ID, Name: "github-token", EnvName: "GITHUB_TOKEN", Value: "ghp_xxxx"} - secret1 := dbgen.UserSecret(t, db, insert1, func(p *database.CreateUserSecretParams) { p.FilePath = "" }) - - insert2 := database.UserSecret{ID: uuid.New(), UserID: user.ID, Name: "ssh-key", FilePath: "~/.ssh/id_rsa", Value: "private-key"} - secret2 := dbgen.UserSecret(t, db, insert2, func(p *database.CreateUserSecretParams) { p.EnvName = "" }) - - insert3 := database.UserSecret{ID: uuid.New(), UserID: user.ID, Name: "both", EnvName: "BOTH", FilePath: "/etc/both", Value: "both-val"} - secret3 := dbgen.UserSecret(t, db, insert3) - - insert4 := database.UserSecret{ID: uuid.New(), UserID: user.ID, Name: "empty-value", Value: "", EnvName: "EMPTY_VALUE", FilePath: "/etc/empty-value"} - secret4 := dbgen.UserSecret(t, db, insert4, func(p *database.CreateUserSecretParams) { p.Value = "" }) - - insert5 := database.UserSecret{ID: uuid.New(), UserID: user.ID, Name: "no-injection", Value: "no-injection"} - _ = dbgen.UserSecret(t, db, insert5, func(p *database.CreateUserSecretParams) { p.EnvName = ""; p.FilePath = "" }) - - template := dbgen.Template(t, db, database.Template{ - Name: "template", - Provisioner: database.ProvisionerTypeEcho, - OrganizationID: pd.OrganizationID, - CreatedBy: user.ID, - }) - file := dbgen.File(t, db, database.File{CreatedBy: user.ID}) - version := dbgen.TemplateVersion(t, db, database.TemplateVersion{ - CreatedBy: user.ID, - OrganizationID: pd.OrganizationID, - TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true}, - JobID: uuid.New(), - }) - // Import version job - _ = dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{ - OrganizationID: pd.OrganizationID, - ID: version.JobID, - InitiatorID: user.ID, - FileID: file.ID, - Provisioner: database.ProvisionerTypeEcho, - StorageMethod: database.ProvisionerStorageMethodFile, - Type: database.ProvisionerJobTypeTemplateVersionImport, - Input: must(json.Marshal(provisionerdserver.TemplateVersionImportJob{ - TemplateVersionID: version.ID, - })), - }) - workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ - TemplateID: template.ID, - OwnerID: user.ID, - OrganizationID: pd.OrganizationID, - }) - buildID := uuid.New() - dbJob := dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{ - OrganizationID: pd.OrganizationID, - InitiatorID: user.ID, - Provisioner: database.ProvisionerTypeEcho, - StorageMethod: database.ProvisionerStorageMethodFile, - FileID: file.ID, - Type: database.ProvisionerJobTypeWorkspaceBuild, - Input: must(json.Marshal(provisionerdserver.WorkspaceProvisionJob{ - WorkspaceBuildID: buildID, - })), - Tags: pd.Tags, - }) - _ = dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ - ID: buildID, - WorkspaceID: workspace.ID, - BuildNumber: 1, - JobID: dbJob.ID, - TemplateVersionID: version.ID, - Transition: database.WorkspaceTransitionStart, - Reason: database.BuildReasonInitiator, - }) - - startPublished := make(chan struct{}) - var closed bool - closeStartSubscribe, err := ps.SubscribeWithErr(wspubsub.WorkspaceEventChannel(workspace.OwnerID), - wspubsub.HandleWorkspaceEvent( - func(_ context.Context, e wspubsub.WorkspaceEvent, err error) { - if err != nil { - return - } - if e.Kind == wspubsub.WorkspaceEventKindStateChange && e.WorkspaceID == workspace.ID { - if !closed { - close(startPublished) - closed = true - } - } - })) - require.NoError(t, err) - defer closeStartSubscribe() - - // Grab jobs until we find the workspace build job. - var job *proto.AcquiredJob - testutil.Eventually(ctx, t, func(ctx context.Context) bool { - job, err = tc.acquire(ctx, srv) - require.NoError(t, err) - _, ok := job.Type.(*proto.AcquiredJob_WorkspaceBuild_) - return ok - }, testutil.IntervalMedium) - - select { - case <-startPublished: - case <-time.After(testutil.WaitShort): - t.Fatalf("timed out waiting for workspace build job to start") - } - - wb := job.Type.(*proto.AcquiredJob_WorkspaceBuild_).WorkspaceBuild - require.Len(t, wb.UserSecrets, 4, "expected 4 secrets (the one with empty env_name and file_path should be filtered)") - - // Re-sort by (env_name+file_path) before asserting field values. - // The terraform-provider-coder contract does not require a - // specific secret order, so this test intentionally does not - // assert the order produced by ListUserSecretsWithValues. - slices.SortFunc(wb.UserSecrets, func(a, b *sdkproto.UserSecretValue) int { - return strings.Compare(a.EnvName+a.FilePath, b.EnvName+b.FilePath) - }) - - // After sorting: []{secret3, secret4, secret1, secret2} - require.Equal(t, secret3.EnvName, wb.UserSecrets[0].EnvName) - require.Equal(t, secret3.FilePath, wb.UserSecrets[0].FilePath) - require.Equal(t, []byte(secret3.Value), wb.UserSecrets[0].Value) - - require.Equal(t, secret4.EnvName, wb.UserSecrets[1].EnvName) - require.Equal(t, secret4.FilePath, wb.UserSecrets[1].FilePath) - require.Equal(t, []byte(secret4.Value), wb.UserSecrets[1].Value) - - require.Equal(t, secret1.EnvName, wb.UserSecrets[2].EnvName) - require.Equal(t, secret1.FilePath, wb.UserSecrets[2].FilePath) - require.Equal(t, []byte(secret1.Value), wb.UserSecrets[2].Value) - - require.Equal(t, secret2.EnvName, wb.UserSecrets[3].EnvName) - require.Equal(t, secret2.FilePath, wb.UserSecrets[3].FilePath) - require.Equal(t, []byte(secret2.Value), wb.UserSecrets[3].Value) - }) - - for _, transitionCase := range []struct { - name string - transition database.WorkspaceTransition - }{ - { - name: "Stop", - transition: database.WorkspaceTransitionStop, - }, - { - name: "Delete", - transition: database.WorkspaceTransitionDelete, - }, - } { - t.Run(tc.name+"_UserSecrets"+transitionCase.name+"Transition", func(t *testing.T) { - // Secrets must never be populated on non-start transitions. The - // terraform-provider-coder data source intentionally returns empty - // values on stop/delete so that workspaces with revoked or deleted - // secrets can still be torn down. - t.Parallel() - srv, db, ps, pd := setup(t, false, nil) - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) - defer cancel() - - user := dbgen.User(t, db, database.User{}) - dbgen.OrganizationMember(t, db, database.OrganizationMember{ - UserID: user.ID, - OrganizationID: pd.OrganizationID, - }) - dbgen.GitSSHKey(t, db, database.GitSSHKey{UserID: user.ID}) - - // Give the owner a secret so we can prove it is not forwarded on a - // transition. - authCtx := dbauthz.AsSystemRestricted(ctx) - _, err := db.CreateUserSecret(authCtx, database.CreateUserSecretParams{ - ID: uuid.New(), - UserID: user.ID, - Name: "github-token", - EnvName: "GITHUB_TOKEN", - Value: "must-not-leak", - }) - require.NoError(t, err) - - template := dbgen.Template(t, db, database.Template{ - Name: "template", - Provisioner: database.ProvisionerTypeEcho, - OrganizationID: pd.OrganizationID, - CreatedBy: user.ID, - }) - file := dbgen.File(t, db, database.File{CreatedBy: user.ID}) - version := dbgen.TemplateVersion(t, db, database.TemplateVersion{ - CreatedBy: user.ID, - OrganizationID: pd.OrganizationID, - TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true}, - JobID: uuid.New(), - }) - _ = dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{ - OrganizationID: pd.OrganizationID, - ID: version.JobID, - InitiatorID: user.ID, - FileID: file.ID, - Provisioner: database.ProvisionerTypeEcho, - StorageMethod: database.ProvisionerStorageMethodFile, - Type: database.ProvisionerJobTypeTemplateVersionImport, - Input: must(json.Marshal(provisionerdserver.TemplateVersionImportJob{ - TemplateVersionID: version.ID, - })), - }) - workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ - TemplateID: template.ID, - OwnerID: user.ID, - OrganizationID: pd.OrganizationID, - }) - buildID := uuid.New() - dbJob := dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{ - OrganizationID: pd.OrganizationID, - InitiatorID: user.ID, - Provisioner: database.ProvisionerTypeEcho, - StorageMethod: database.ProvisionerStorageMethodFile, - FileID: file.ID, - Type: database.ProvisionerJobTypeWorkspaceBuild, - Input: must(json.Marshal(provisionerdserver.WorkspaceProvisionJob{ - WorkspaceBuildID: buildID, - })), - Tags: pd.Tags, - }) - _ = dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ - ID: buildID, - WorkspaceID: workspace.ID, - BuildNumber: 1, - JobID: dbJob.ID, - TemplateVersionID: version.ID, - Transition: transitionCase.transition, - Reason: database.BuildReasonInitiator, - }) - - var job *proto.AcquiredJob - for { - job, err = tc.acquire(ctx, srv) - require.NoError(t, err) - if _, ok := job.Type.(*proto.AcquiredJob_WorkspaceBuild_); ok { - break - } - } - - wb := job.Type.(*proto.AcquiredJob_WorkspaceBuild_).WorkspaceBuild - require.Empty(t, wb.UserSecrets) - }) - } - - t.Run(tc.name+"_UserSecretsDBError", func(t *testing.T) { - // A DB failure fetching user secrets must surface as a provisioner - // job failure rather than being silently treated as "no secrets". - // Silent treatment would let a transient DB error cause a - // workspace to build without the secrets it needs, producing a - // confusing downstream terraform error about missing secrets that - // the user actually owns. - t.Parallel() - srv, db, ps, pd := setup(t, true, &overrides{ - wrapDB: func(inner database.Store) database.Store { - return &errOnListUserSecretsWithValues{Store: inner} - }, - }) - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort) - defer cancel() - - user := dbgen.User(t, db, database.User{}) - dbgen.OrganizationMember(t, db, database.OrganizationMember{ - UserID: user.ID, - OrganizationID: pd.OrganizationID, - }) - dbgen.GitSSHKey(t, db, database.GitSSHKey{UserID: user.ID}) - - template := dbgen.Template(t, db, database.Template{ - Name: "template", - Provisioner: database.ProvisionerTypeEcho, - OrganizationID: pd.OrganizationID, - CreatedBy: user.ID, - }) - file := dbgen.File(t, db, database.File{CreatedBy: user.ID}) - version := dbgen.TemplateVersion(t, db, database.TemplateVersion{ - CreatedBy: user.ID, - OrganizationID: pd.OrganizationID, - TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true}, - JobID: uuid.New(), - }) - _ = dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{ - OrganizationID: pd.OrganizationID, - ID: version.JobID, - InitiatorID: user.ID, - FileID: file.ID, - Provisioner: database.ProvisionerTypeEcho, - StorageMethod: database.ProvisionerStorageMethodFile, - Type: database.ProvisionerJobTypeTemplateVersionImport, - Input: must(json.Marshal(provisionerdserver.TemplateVersionImportJob{ - TemplateVersionID: version.ID, - })), - }) - workspace := dbgen.Workspace(t, db, database.WorkspaceTable{ - TemplateID: template.ID, - OwnerID: user.ID, - OrganizationID: pd.OrganizationID, - }) - buildID := uuid.New() - dbJob := dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{ - OrganizationID: pd.OrganizationID, - InitiatorID: user.ID, - Provisioner: database.ProvisionerTypeEcho, - StorageMethod: database.ProvisionerStorageMethodFile, - FileID: file.ID, - Type: database.ProvisionerJobTypeWorkspaceBuild, - Input: must(json.Marshal(provisionerdserver.WorkspaceProvisionJob{ - WorkspaceBuildID: buildID, - })), - Tags: pd.Tags, - }) - _ = dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{ - ID: buildID, - WorkspaceID: workspace.ID, - BuildNumber: 1, - JobID: dbJob.ID, - TemplateVersionID: version.ID, - // Only start transitions fetch secrets. - Transition: database.WorkspaceTransitionStart, - Reason: database.BuildReasonInitiator, - }) - - var acquireErr error - for { - // Keep acquiring until we either get our build back (possible - // for the Deprecated path to return an empty AcquiredJob once - // its long-poll window elapses on unrelated jobs) or propagate - // an error. - job, err := tc.acquire(ctx, srv) - if err != nil { - acquireErr = err - break - } - if job != nil && job.JobId != "" { - t.Fatalf("expected acquire to error, got job %s", job.JobId) - } - } - require.ErrorContains(t, acquireErr, "request job was invalidated", - "DB error should surface as a job invalidation") - require.ErrorContains(t, acquireErr, "get user secrets", - "error should identify the failing operation") - require.ErrorContains(t, acquireErr, "ListUserSecretsWithValues query failed", - "underlying DB error message should be preserved") - - // Confirm the provisioner job itself was marked as failed so the - // workspace build does not remain stuck in-progress. - authCtx := dbauthz.AsSystemRestricted(ctx) - gotJob, err := db.GetProvisionerJobByID(authCtx, dbJob.ID) - require.NoError(t, err) - require.True(t, gotJob.Error.Valid, "job should be marked with an error") - require.Contains(t, gotJob.Error.String, "get user secrets") - require.True(t, gotJob.CompletedAt.Valid, "job should be marked complete") - }) } } @@ -5157,9 +4795,6 @@ type overrides struct { auditor audit.Auditor notificationEnqueuer notifications.Enqueuer prebuildsOrchestrator agplprebuilds.ReconciliationOrchestrator - // wrapDB wraps the raw DB before dbauthz.New. Use this to inject - // errors or observe calls on specific queries for a single test. - wrapDB func(database.Store) database.Store } func setup(t *testing.T, ignoreLogErrors bool, ov *overrides) (proto.DRPCProvisionerDaemonServer, database.Store, pubsub.Pubsub, database.ProvisionerDaemon) { @@ -5260,9 +4895,6 @@ func setup(t *testing.T, ignoreLogErrors bool, ov *overrides) (proto.DRPCProvisi // Use an authz wrapped database for the server to ensure permission checks // work. authorizer := rbac.NewStrictCachingAuthorizer(prometheus.NewRegistry()) - if ov.wrapDB != nil { - db = ov.wrapDB(db) - } serverDB := dbauthz.New(db, authorizer, logger, coderdtest.AccessControlStorePointer()) srv, err := provisionerdserver.NewServer( ov.ctx, @@ -5407,32 +5039,3 @@ func newFakeUsageInserter() (*coderdtest.UsageInserter, *atomic.Pointer[usage.In poitr.Store(&inserter) return fake, poitr } - -// errListUserSecretsWithValues is the sentinel returned by the test wrapper -// below. Its message is matched by assertions that verify the underlying DB -// error propagated through failJob's formatting. The chain is not preserved -// via errors.Is because failJob uses fmt.Sprintf, not %w. -var errListUserSecretsWithValues = xerrors.New("ListUserSecretsWithValues query failed") - -// errOnListUserSecretsWithValues is a database.Store wrapper that errors only -// on ListUserSecretsWithValues. All other methods pass through to the -// underlying store. Used to simulate a transient DB failure on the secret -// fetch without breaking the rest of the acquire flow (user lookup, job -// update, etc.). -type errOnListUserSecretsWithValues struct { - database.Store -} - -func (*errOnListUserSecretsWithValues) ListUserSecretsWithValues(context.Context, uuid.UUID) ([]database.UserSecret, error) { - return nil, errListUserSecretsWithValues -} - -// InTx must be overridden to keep the wrapped store visible inside a -// transaction. Without this override, InTx would pass the raw inner store to -// its closure and tests would see the unwrapped behavior from anywhere that -// runs inside a transaction. -func (e *errOnListUserSecretsWithValues) InTx(fn func(database.Store) error, opts *database.TxOptions) error { - return e.Store.InTx(func(tx database.Store) error { - return fn(&errOnListUserSecretsWithValues{Store: tx}) - }, opts) -} diff --git a/coderd/testdata/parameters/secret_required/main.tf b/coderd/testdata/parameters/secret_required/main.tf deleted file mode 100644 index 98434c5a26..0000000000 --- a/coderd/testdata/parameters/secret_required/main.tf +++ /dev/null @@ -1,12 +0,0 @@ -terraform { - required_providers { - coder = { - source = "coder/coder" - } - } -} - -data "coder_secret" "gh" { - env = "GITHUB_TOKEN" - help_message = "Add a GitHub PAT with env=GITHUB_TOKEN" -} diff --git a/coderd/usersecrets.go b/coderd/usersecrets.go index 09be0a964d..7bcfc5d0f6 100644 --- a/coderd/usersecrets.go +++ b/coderd/usersecrets.go @@ -10,13 +10,11 @@ import ( "github.com/google/uuid" "golang.org/x/xerrors" - "cdr.dev/slog/v3" "github.com/coder/coder/v2/coderd/audit" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/db2sdk" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" - "github.com/coder/coder/v2/coderd/usersecretspubsub" "github.com/coder/coder/v2/codersdk" ) @@ -84,14 +82,6 @@ func (api *API) postUserSecret(rw http.ResponseWriter, r *http.Request) { } aReq.New = secret - api.publishUserSecretEvent(ctx, usersecretspubsub.Event{ - Kind: usersecretspubsub.EventKindCreated, - UserID: secret.UserID, - Name: secret.Name, - EnvName: secret.EnvName, - FilePath: secret.FilePath, - }) - httpapi.Write(ctx, rw, http.StatusCreated, db2sdk.UserSecretFromFull(secret)) } @@ -263,14 +253,6 @@ func (api *API) patchUserSecret(rw http.ResponseWriter, r *http.Request) { return } - api.publishUserSecretEvent(ctx, usersecretspubsub.Event{ - Kind: usersecretspubsub.EventKindUpdated, - UserID: secret.UserID, - Name: secret.Name, - EnvName: secret.EnvName, - FilePath: secret.FilePath, - }) - httpapi.Write(ctx, rw, http.StatusOK, db2sdk.UserSecretFromFull(secret)) } @@ -314,12 +296,6 @@ func (api *API) deleteUserSecret(rw http.ResponseWriter, r *http.Request) { } aReq.Old = deleted - api.publishUserSecretEvent(ctx, usersecretspubsub.Event{ - Kind: usersecretspubsub.EventKindDeleted, - UserID: user.ID, - Name: name, - }) - rw.WriteHeader(http.StatusNoContent) } @@ -391,14 +367,3 @@ func userSecretConflictValidationErrors(err error) []codersdk.ValidationError { return nil } } - -func (api *API) publishUserSecretEvent(ctx context.Context, event usersecretspubsub.Event) { - if err := usersecretspubsub.Publish(api.Pubsub, event); err != nil { - api.Logger.Warn(ctx, "failed to publish user secret event", - slog.F("user_id", event.UserID), - slog.F("secret_name", event.Name), - slog.F("event_kind", event.Kind), - slog.Error(err), - ) - } -} diff --git a/coderd/usersecretspubsub/usersecretspubsub.go b/coderd/usersecretspubsub/usersecretspubsub.go deleted file mode 100644 index 39fb5c0759..0000000000 --- a/coderd/usersecretspubsub/usersecretspubsub.go +++ /dev/null @@ -1,42 +0,0 @@ -package usersecretspubsub - -import ( - "encoding/json" - "fmt" - - "github.com/google/uuid" - "golang.org/x/xerrors" - - "github.com/coder/coder/v2/coderd/database/pubsub" -) - -type EventKind string - -const ( - EventKindCreated EventKind = "created" - EventKindUpdated EventKind = "updated" - EventKindDeleted EventKind = "deleted" -) - -type Event struct { - Kind EventKind `json:"kind"` - UserID uuid.UUID `json:"user_id" format:"uuid"` - Name string `json:"name"` - EnvName string `json:"env_name,omitempty"` - FilePath string `json:"file_path,omitempty"` -} - -func Channel(userID uuid.UUID) string { - return fmt.Sprintf("user_secrets:%s", userID) -} - -func Publish(ps pubsub.Publisher, event Event) error { - msg, err := json.Marshal(event) - if err != nil { - return xerrors.Errorf("marshal user secret event: %w", err) - } - if err := ps.Publish(Channel(event.UserID), msg); err != nil { - return xerrors.Errorf("publish user secret event: %w", err) - } - return nil -} diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index fdaaccacfc..8ccb6417b8 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -383,7 +383,6 @@ func (api *API) postWorkspaceBuildsInternal( DeploymentValues(api.Options.DeploymentValues). Experiments(api.Experiments). TemplateVersionPresetID(createBuild.TemplateVersionPresetID). - Logger(api.Logger.Named("wsbuilder")). BuildMetrics(api.WorkspaceBuilderMetrics) if (transition == database.WorkspaceTransitionStart || transition == database.WorkspaceTransitionStop) && createBuild.Reason != "" { diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 4742189d2f..ed6c5c73b8 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -25,7 +25,6 @@ import ( "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/database/provisionerjobs" - "github.com/coder/coder/v2/coderd/dynamicparameters" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpapi/httperror" "github.com/coder/coder/v2/coderd/httpmw" @@ -795,7 +794,6 @@ func createWorkspace( Experiments(api.Experiments). DeploymentValues(api.DeploymentValues). RichParameterValues(req.RichParameterValues). - Logger(api.Logger.Named("wsbuilder")). BuildMetrics(api.WorkspaceBuilderMetrics) if req.TemplateVersionID != uuid.Nil { builder = builder.VersionID(req.TemplateVersionID) @@ -2010,36 +2008,6 @@ func (api *API) resolveAutostart(rw http.ResponseWriter, r *http.Request) { break } } - - // Surface whether the active template version declares coder_secret - // requirements that the workspace owner's secrets do not satisfy. The - // intention is for this information to inform the workspace update - // requirement so the user knows autostart will not run an auto-update - // build until the missing secrets are satisfied. - // - // Callers without user_secret:read on the workspace owner produce a - // forbidden warning diagnostic. This is treated as "unknown" and - // no mismatch is reported rather than returning a partial answer. - secretMismatch, err := dynamicparameters.EvaluateSecretMismatch( - ctx, - api.Logger.Named("dynamicparameters"), - api.Database, api.FileCache, version, workspace.OwnerID, dbBuildParams, - ) - switch { - case err == nil: - response.SecretMismatch = secretMismatch - case xerrors.Is(err, dynamicparameters.ErrTemplateVersionNotReady): - // Active version's provisioner job hasn't completed yet. Leave - // SecretMismatch false. - default: - // Don't drop the already-computed ParameterMismatch signal on a - // renderer infrastructure error. Log and treat as "unknown." - api.Logger.Warn(ctx, "failed to evaluate secret requirements", - slog.F("workspace_id", workspace.ID), - slog.Error(err), - ) - } - httpapi.Write(ctx, rw, http.StatusOK, response) } diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go index e27a2f9868..653f90969f 100644 --- a/coderd/wsbuilder/wsbuilder.go +++ b/coderd/wsbuilder/wsbuilder.go @@ -17,7 +17,6 @@ import ( "github.com/sqlc-dev/pqtype" "golang.org/x/xerrors" - "cdr.dev/slog/v3" "github.com/coder/coder/v2/coderd/audit" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/db2sdk" @@ -60,7 +59,6 @@ type Builder struct { deploymentValues *codersdk.DeploymentValues experiments codersdk.Experiments usageChecker UsageChecker - logger slog.Logger richParameterValues []codersdk.WorkspaceBuildParameter initiator uuid.UUID @@ -197,12 +195,6 @@ func (b Builder) Experiments(exp codersdk.Experiments) Builder { return b } -func (b Builder) Logger(log slog.Logger) Builder { - // nolint: revive - b.logger = log - return b -} - func (b Builder) Initiator(u uuid.UUID) Builder { // nolint: revive b.initiator = u @@ -776,7 +768,6 @@ func (b *Builder) getDynamicParameterRenderer() (dynamicparameters.Renderer, err dynamicparameters.WithProvisionerJob(*job), dynamicparameters.WithTerraformValues(*tfVals), dynamicparameters.WithTemplateVariableValues(variableValues), - dynamicparameters.WithLogger(b.logger.Named("dynamicparameters")), ) if err != nil { return nil, xerrors.Errorf("get template version renderer: %w", err) @@ -902,16 +893,10 @@ func (b *Builder) getDynamicParameters() (names, values []string, err error) { return nil, nil, BuildError{http.StatusInternalServerError, "failed to check if first build", err} } - // Don't let missing secrets block stop or delete. - var resolveOpts []dynamicparameters.ResolveOption - if b.trans != database.WorkspaceTransitionStart { - resolveOpts = append(resolveOpts, dynamicparameters.SkipSecretRequirements()) - } buildValues, err := dynamicparameters.ResolveParameters(b.ctx, b.workspace.OwnerID, render, firstBuild, lastBuildParameters, b.richParameterValues, - presetParameterValues, - resolveOpts...) + presetParameterValues) if err != nil { return nil, nil, BuildError{http.StatusBadRequest, "resolve parameters", err} } @@ -1147,13 +1132,13 @@ func (b *Builder) getDynamicProvisionerTags() (map[string]string, error) { vals[name] = values[i] } - result, diags := render.Render(b.ctx, b.workspace.OwnerID, vals) - tagErr := dynamicparameters.CheckTags(result.Output, diags) + output, diags := render.Render(b.ctx, b.workspace.OwnerID, vals) + tagErr := dynamicparameters.CheckTags(output, diags) if tagErr != nil { return nil, BuildError{http.StatusBadRequest, "workspace tags validation failed", tagErr} } - for k, v := range result.Output.WorkspaceTags.Tags() { + for k, v := range output.WorkspaceTags.Tags() { tags[k] = v } diff --git a/coderd/wsbuilder/wsbuilder_internal_test.go b/coderd/wsbuilder/wsbuilder_internal_test.go deleted file mode 100644 index 92f313b82b..0000000000 --- a/coderd/wsbuilder/wsbuilder_internal_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package wsbuilder - -import ( - "context" - "testing" - - "github.com/google/uuid" - "github.com/hashicorp/hcl/v2" - "github.com/stretchr/testify/require" - - "github.com/coder/coder/v2/coderd/database" - "github.com/coder/coder/v2/coderd/dynamicparameters" - "github.com/coder/coder/v2/provisionersdk" - "github.com/coder/preview" - previewtypes "github.com/coder/preview/types" -) - -func TestBuilderDynamicProvisionerTagsDoesNotRequestSecretRequirements(t *testing.T) { - t.Parallel() - - ownerID := uuid.New() - names := []string{"region"} - values := []string{"us-east"} - - render := &tagsPathRenderer{ - result: &dynamicparameters.RenderResult{ - Output: &preview.Output{ - WorkspaceTags: previewtypes.TagBlocks{{ - Tags: previewtypes.Tags{{ - Key: previewtypes.StringLiteral("region"), - Value: previewtypes.StringLiteral("us-east"), - }}, - }}, - }, - }, - } - - builder := New(database.Workspace{ - ID: uuid.New(), - OwnerID: ownerID, - }, database.WorkspaceTransitionStart, NoopUsageChecker{}) - builder.ctx = t.Context() - builder.parameterRender = render - builder.parameterNames = &names - builder.parameterValues = &values - builder.templateVersionJob = &database.ProvisionerJob{ - Tags: database.StringMap{ - provisionersdk.TagScope: provisionersdk.ScopeUser, - }, - } - - tags, err := builder.getDynamicProvisionerTags() - require.NoError(t, err) - require.Equal(t, "us-east", tags["region"]) - require.Equal(t, ownerID.String(), tags[provisionersdk.TagOwner]) - require.Empty(t, render.opts, "tags path should not request secret requirements") -} - -type tagsPathRenderer struct { - result *dynamicparameters.RenderResult - diags hcl.Diagnostics - opts []dynamicparameters.RenderOption -} - -func (r *tagsPathRenderer) Render(_ context.Context, _ uuid.UUID, _ map[string]string, opts ...dynamicparameters.RenderOption) (*dynamicparameters.RenderResult, hcl.Diagnostics) { - r.opts = opts - return r.result, r.diags -} - -func (*tagsPathRenderer) Close() {} diff --git a/codersdk/parameters.go b/codersdk/parameters.go index 7f6c9cdad1..937fbe4005 100644 --- a/codersdk/parameters.go +++ b/codersdk/parameters.go @@ -162,27 +162,18 @@ type PreviewParameterValidation struct { } type DynamicParametersRequest struct { - // ID identifies the request for response ordering. Websocket response - // IDs are monotonically increasing and may exceed the request ID when - // server-side events trigger additional renders. + // ID identifies the request. The response contains the same + // ID so that the client can match it to the request. ID int `json:"id"` Inputs map[string]string `json:"inputs"` // OwnerID if uuid.Nil, it defaults to `codersdk.Me` OwnerID uuid.UUID `json:"owner_id,omitempty" format:"uuid"` } -type SecretRequirementStatus struct { - Env string `json:"env,omitempty"` - File string `json:"file,omitempty"` - HelpMessage string `json:"help_message"` - Satisfied bool `json:"satisfied"` -} - type DynamicParametersResponse struct { - ID int `json:"id"` - Diagnostics []FriendlyDiagnostic `json:"diagnostics"` - Parameters []PreviewParameter `json:"parameters"` - SecretRequirements []SecretRequirementStatus `json:"secret_requirements,omitempty"` + ID int `json:"id"` + Diagnostics []FriendlyDiagnostic `json:"diagnostics"` + Parameters []PreviewParameter `json:"parameters"` // TODO: Workspace tags } diff --git a/codersdk/workspaces.go b/codersdk/workspaces.go index e1fbbd859b..b520f27e4f 100644 --- a/codersdk/workspaces.go +++ b/codersdk/workspaces.go @@ -680,10 +680,6 @@ func (c *Client) WorkspaceQuota(ctx context.Context, organizationID string, user type ResolveAutostartResponse struct { ParameterMismatch bool `json:"parameter_mismatch"` - // SecretMismatch is true when the active template version declares - // `coder_secret` requirements that the workspace owner's secrets do not - // satisfy. - SecretMismatch bool `json:"secret_mismatch"` } func (c *Client) ResolveAutostart(ctx context.Context, workspaceID string) (ResolveAutostartResponse, error) { diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 8f126090e5..7e3ab345e1 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -6897,12 +6897,12 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o ### Properties -| Name | Type | Required | Restrictions | Description | -|--------------------|---------|----------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `id` | integer | false | | ID identifies the request for response ordering. Websocket response IDs are monotonically increasing and may exceed the request ID when server-side events trigger additional renders. | -| `inputs` | object | false | | | -| » `[any property]` | string | false | | | -| `owner_id` | string | false | | Owner ID if uuid.Nil, it defaults to `codersdk.Me` | +| Name | Type | Required | Restrictions | Description | +|--------------------|---------|----------|--------------|--------------------------------------------------------------------------------------------------------------| +| `id` | integer | false | | ID identifies the request. The response contains the same ID so that the client can match it to the request. | +| `inputs` | object | false | | | +| » `[any property]` | string | false | | | +| `owner_id` | string | false | | Owner ID if uuid.Nil, it defaults to `codersdk.Me` | ## codersdk.DynamicParametersResponse @@ -6976,26 +6976,17 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o "value": "string" } } - ], - "secret_requirements": [ - { - "env": "string", - "file": "string", - "help_message": "string", - "satisfied": true - } ] } ``` ### Properties -| Name | Type | Required | Restrictions | Description | -|-----------------------|-------------------------------------------------------------------------------|----------|--------------|-------------| -| `diagnostics` | array of [codersdk.FriendlyDiagnostic](#codersdkfriendlydiagnostic) | false | | | -| `id` | integer | false | | | -| `parameters` | array of [codersdk.PreviewParameter](#codersdkpreviewparameter) | false | | | -| `secret_requirements` | array of [codersdk.SecretRequirementStatus](#codersdksecretrequirementstatus) | false | | | +| Name | Type | Required | Restrictions | Description | +|---------------|---------------------------------------------------------------------|----------|--------------|-------------| +| `diagnostics` | array of [codersdk.FriendlyDiagnostic](#codersdkfriendlydiagnostic) | false | | | +| `id` | integer | false | | | +| `parameters` | array of [codersdk.PreviewParameter](#codersdkpreviewparameter) | false | | | ## codersdk.DynamicTool @@ -11074,17 +11065,15 @@ Only certain features set these fields: - FeatureManagedAgentLimit| ```json { - "parameter_mismatch": true, - "secret_mismatch": true + "parameter_mismatch": true } ``` ### Properties -| Name | Type | Required | Restrictions | Description | -|----------------------|---------|----------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------| -| `parameter_mismatch` | boolean | false | | | -| `secret_mismatch` | boolean | false | | Secret mismatch is true when the active template version declares `coder_secret` requirements that the workspace owner's secrets do not satisfy. | +| Name | Type | Required | Restrictions | Description | +|----------------------|---------|----------|--------------|-------------| +| `parameter_mismatch` | boolean | false | | | ## codersdk.ResourceType @@ -11479,26 +11468,6 @@ Only certain features set these fields: - FeatureManagedAgentLimit| | `ssh_config_options` | object | false | | | | » `[any property]` | string | false | | | -## codersdk.SecretRequirementStatus - -```json -{ - "env": "string", - "file": "string", - "help_message": "string", - "satisfied": true -} -``` - -### Properties - -| Name | Type | Required | Restrictions | Description | -|----------------|---------|----------|--------------|-------------| -| `env` | string | false | | | -| `file` | string | false | | | -| `help_message` | string | false | | | -| `satisfied` | boolean | false | | | - ## codersdk.ServerSentEvent ```json diff --git a/docs/reference/api/templates.md b/docs/reference/api/templates.md index 37a19b3acf..6deddeb2a5 100644 --- a/docs/reference/api/templates.md +++ b/docs/reference/api/templates.md @@ -2802,14 +2802,6 @@ curl -X POST http://coder-server:8080/api/v2/templateversions/{templateversion}/ "value": "string" } } - ], - "secret_requirements": [ - { - "env": "string", - "file": "string", - "help_message": "string", - "satisfied": true - } ] } ``` diff --git a/docs/reference/api/workspaces.md b/docs/reference/api/workspaces.md index 82fdea7c39..2d00a98d83 100644 --- a/docs/reference/api/workspaces.md +++ b/docs/reference/api/workspaces.md @@ -2386,8 +2386,7 @@ curl -X GET http://coder-server:8080/api/v2/workspaces/{workspace}/resolve-autos ```json { - "parameter_mismatch": true, - "secret_mismatch": true + "parameter_mismatch": true } ``` diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index 01f52cce2c..592bc3c9cc 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -198,7 +198,7 @@ func (s *server) Plan( } } - env, err := provisionEnv(sess.Config, request.Metadata, request.PreviousParameterValues, request.RichParameterValues, request.ExternalAuthProviders, request.UserSecrets) + env, err := provisionEnv(sess.Config, request.Metadata, request.PreviousParameterValues, request.RichParameterValues, request.ExternalAuthProviders) if err != nil { return provisionersdk.PlanErrorf("setup env: %s", err) } @@ -311,7 +311,7 @@ func (s *server) Apply( } } - env, err := provisionEnv(sess.Config, request.Metadata, nil, nil, nil, nil) + env, err := provisionEnv(sess.Config, request.Metadata, nil, nil, nil) if err != nil { return provisionersdk.ApplyErrorf("provision env: %s", err) } @@ -347,7 +347,6 @@ func planVars(plan *proto.PlanRequest) ([]string, error) { func provisionEnv( config *proto.Config, metadata *proto.Metadata, previousParams, richParams []*proto.RichParameterValue, externalAuth []*proto.ExternalAuthProvider, - userSecrets []*proto.UserSecretValue, ) ([]string, error) { env := safeEnviron() ownerGroups, err := json.Marshal(metadata.GetWorkspaceOwnerGroups()) @@ -416,19 +415,6 @@ func provisionEnv( env = append(env, provider.ExternalAuthAccessTokenEnvironmentVariable(extAuth.Id)+"="+extAuth.AccessToken) } - for _, secret := range userSecrets { - if secret.EnvName != "" { - env = append(env, provider.SecretEnvEnvironmentVariable(secret.EnvName)+"="+string(secret.Value)) - } - if secret.FilePath != "" { - // Environment variables are used to communicate the file path a - // secret should be written to. The hex encoding is done because - // file paths contain slashes, tildes, and dots that are illegal - // in environment variable names. - env = append(env, provider.SecretFileEnvironmentVariable(secret.FilePath)+"="+string(secret.Value)) - } - } - if config.ProvisionerLogLevel != "" { // TF_LOG=JSON enables all kind of logging: trace-debug-info-warn-error. // The idea behind using TF_LOG=JSON instead of TF_LOG=debug is ensuring the proper log format. diff --git a/provisioner/terraform/provision_internal_test.go b/provisioner/terraform/provision_internal_test.go deleted file mode 100644 index 2b250f2fae..0000000000 --- a/provisioner/terraform/provision_internal_test.go +++ /dev/null @@ -1,119 +0,0 @@ -package terraform - -import ( - "encoding/hex" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/coder/coder/v2/provisionersdk/proto" -) - -func TestProvisionEnv_UserSecrets(t *testing.T) { - t.Parallel() - - t.Run("EnvSecret", func(t *testing.T) { - t.Parallel() - secrets := []*proto.UserSecretValue{ - {EnvName: "MY_TOKEN", Value: []byte("secret-value")}, - } - env, err := provisionEnv(&proto.Config{}, &proto.Metadata{}, nil, nil, nil, secrets) - require.NoError(t, err) - - want := "CODER_SECRET_ENV_MY_TOKEN=secret-value" - assert.Contains(t, env, want) - }) - - t.Run("FileSecret", func(t *testing.T) { - t.Parallel() - filePath := "~/.ssh/id_rsa" - secrets := []*proto.UserSecretValue{ - {FilePath: filePath, Value: []byte("key-data")}, - } - env, err := provisionEnv(&proto.Config{}, &proto.Metadata{}, nil, nil, nil, secrets) - require.NoError(t, err) - - hexPath := hex.EncodeToString([]byte(filePath)) - want := "CODER_SECRET_FILE_" + hexPath + "=key-data" - assert.Contains(t, env, want) - }) - - t.Run("BothEnvAndFile", func(t *testing.T) { - t.Parallel() - filePath := "/tmp/secret.txt" - secrets := []*proto.UserSecretValue{ - {EnvName: "DUAL", FilePath: filePath, Value: []byte("both-value")}, - } - env, err := provisionEnv(&proto.Config{}, &proto.Metadata{}, nil, nil, nil, secrets) - require.NoError(t, err) - - wantEnv := "CODER_SECRET_ENV_DUAL=both-value" - hexPath := hex.EncodeToString([]byte(filePath)) - wantFile := "CODER_SECRET_FILE_" + hexPath + "=both-value" - assert.Contains(t, env, wantEnv) - assert.Contains(t, env, wantFile) - }) - - t.Run("NilSecrets", func(t *testing.T) { - t.Parallel() - env, err := provisionEnv(&proto.Config{}, &proto.Metadata{}, nil, nil, nil, nil) - require.NoError(t, err) - - for _, e := range env { - assert.False(t, strings.HasPrefix(e, "CODER_SECRET_"), - "unexpected secret env var: %s", e) - } - }) - - t.Run("EmptyEnvAndFile", func(t *testing.T) { - t.Parallel() - secrets := []*proto.UserSecretValue{ - {EnvName: "", FilePath: "", Value: []byte("ignored")}, - } - env, err := provisionEnv(&proto.Config{}, &proto.Metadata{}, nil, nil, nil, secrets) - require.NoError(t, err) - - for _, e := range env { - assert.False(t, strings.HasPrefix(e, "CODER_SECRET_"), - "unexpected secret env var: %s", e) - } - }) -} - -// nolint:paralleltest // t.Setenv is incompatible with t.Parallel. -func TestProvisionEnv_HostSecretsStripped(t *testing.T) { - // Host CODER_* env vars must be stripped by safeEnviron before provisionEnv - // appends its own entries. If the order of operations in provisionEnv ever - // changes (e.g. appending before stripping, or adding a post-filter that - // drops CODER_*), this test catches it. The host var below would otherwise - // leak into the terraform environment and could be interpreted as a real - // secret. - t.Setenv("CODER_SECRET_ENV_PREEXISTING", "host-value") - env, err := provisionEnv(&proto.Config{}, &proto.Metadata{}, nil, nil, nil, nil) - require.NoError(t, err) - - for _, e := range env { - assert.False(t, strings.HasPrefix(e, "CODER_SECRET_"), - "host CODER_SECRET_* var leaked into provisioner env: %s", e) - } -} - -// nolint:paralleltest // t.Setenv is incompatible with t.Parallel. -func TestProvisionEnv_InputSecretsSurviveHostCollision(t *testing.T) { - // When the host has a CODER_SECRET_ENV_X var set and the caller also passes - // X in the secrets slice, the caller's value must win. This proves secrets - // are appended after safeEnviron strips the host's CODER_* vars, not before. - t.Setenv("CODER_SECRET_ENV_COLLIDE", "host-value-should-not-win") - secrets := []*proto.UserSecretValue{ - {EnvName: "COLLIDE", Value: []byte("caller-value")}, - } - env, err := provisionEnv(&proto.Config{}, &proto.Metadata{}, nil, nil, nil, secrets) - require.NoError(t, err) - - assert.Contains(t, env, "CODER_SECRET_ENV_COLLIDE=caller-value", - "caller-supplied secret must be present") - assert.NotContains(t, env, "CODER_SECRET_ENV_COLLIDE=host-value-should-not-win", - "host value must be stripped before secrets are appended") -} diff --git a/provisionerd/proto/provisionerd.pb.go b/provisionerd/proto/provisionerd.pb.go index 0041d681fe..3ce33d18b5 100644 --- a/provisionerd/proto/provisionerd.pb.go +++ b/provisionerd/proto/provisionerd.pb.go @@ -927,10 +927,6 @@ type AcquiredJob_WorkspaceBuild struct { // workspace build. Omit these values if the workspace is being created // for the first time. PreviousParameterValues []*proto.RichParameterValue `protobuf:"bytes,10,rep,name=previous_parameter_values,json=previousParameterValues,proto3" json:"previous_parameter_values,omitempty"` - // User secrets belonging to the workspace owner, to be forwarded into the - // plan request sent to the provisioner. Only populated for start - // transitions. - UserSecrets []*proto.UserSecretValue `protobuf:"bytes,12,rep,name=user_secrets,json=userSecrets,proto3" json:"user_secrets,omitempty"` } func (x *AcquiredJob_WorkspaceBuild) Reset() { @@ -1028,13 +1024,6 @@ func (x *AcquiredJob_WorkspaceBuild) GetPreviousParameterValues() []*proto.RichP return nil } -func (x *AcquiredJob_WorkspaceBuild) GetUserSecrets() []*proto.UserSecretValue { - if x != nil { - return x.UserSecrets - } - return nil -} - type AcquiredJob_TemplateImport struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1570,7 +1559,7 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x1a, 0x26, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x07, 0x0a, - 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0xc0, 0x0c, 0x0a, 0x0b, 0x41, 0x63, 0x71, 0x75, 0x69, + 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x85, 0x0c, 0x0a, 0x0b, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, @@ -1603,7 +1592,7 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x63, 0x65, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0xea, 0x04, 0x0a, 0x0e, 0x57, 0x6f, 0x72, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0xaf, 0x04, 0x0a, 0x0e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, @@ -1637,266 +1626,262 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x17, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, - 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x0c, 0x75, 0x73, 0x65, 0x72, - 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x55, 0x73, 0x65, - 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x75, 0x73, - 0x65, 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, - 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x1a, 0x91, 0x01, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, - 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x4c, 0x0a, 0x14, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x75, 0x73, 0x65, 0x72, 0x56, 0x61, 0x72, 0x69, 0x61, - 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x1a, 0xe3, 0x01, 0x0a, 0x0e, 0x54, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x53, 0x0a, 0x15, - 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, 0x69, - 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, - 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, - 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, - 0x40, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 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, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xd4, 0x03, 0x0a, 0x09, 0x46, 0x61, - 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x14, - 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x12, 0x51, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, 0x61, 0x69, - 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x00, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x51, 0x0a, 0x0f, 0x74, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, - 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, - 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x74, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x52, 0x0a, 0x10, 0x74, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x64, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x48, 0x00, 0x52, 0x0e, - 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x1d, - 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x1a, 0x55, 0x0a, - 0x0e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, - 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2d, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x74, 0x69, 0x6d, - 0x69, 0x6e, 0x67, 0x73, 0x1a, 0x10, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x1a, 0x10, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, - 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x22, 0x89, 0x0b, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, - 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x54, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, - 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x57, 0x6f, - 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x00, 0x52, 0x0e, - 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x54, - 0x0a, 0x0f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6d, 0x70, 0x6f, 0x72, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, - 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, - 0x72, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, - 0x70, 0x6f, 0x72, 0x74, 0x12, 0x55, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x5f, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, - 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x74, 0x65, 0x6d, - 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x1a, 0xc0, 0x02, 0x0a, 0x0e, - 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x14, - 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, - 0x74, 0x61, 0x74, 0x65, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x74, 0x69, 0x6d, - 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x52, - 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, - 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x07, - 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x55, 0x0a, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x70, - 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2e, - 0x0a, 0x08, 0x61, 0x69, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, - 0x49, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x07, 0x61, 0x69, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x1a, 0x9d, - 0x05, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, - 0x74, 0x12, 0x3e, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x52, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x12, 0x3c, 0x0a, 0x0e, 0x73, 0x74, 0x6f, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, - 0x43, 0x0a, 0x0f, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x65, 0x74, 0x65, 0x72, 0x52, 0x0e, 0x72, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x73, 0x12, 0x41, 0x0a, 0x1d, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x1a, 0x65, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x61, 0x0a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, - 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, - 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x38, 0x0a, 0x0d, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4d, 0x6f, 0x64, - 0x75, 0x6c, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x18, - 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x65, 0x73, 0x65, 0x74, 0x52, 0x07, 0x70, 0x72, 0x65, 0x73, - 0x65, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x6f, 0x64, 0x75, 0x6c, - 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6d, - 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x6f, - 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, - 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x69, 0x6c, - 0x65, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x20, 0x0a, 0x0c, 0x68, 0x61, 0x73, 0x5f, 0x61, 0x69, - 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x68, 0x61, - 0x73, 0x41, 0x69, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x68, 0x61, 0x73, 0x5f, - 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, - 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x68, 0x61, 0x73, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x1a, 0x74, - 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, - 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x07, 0x6d, 0x6f, 0x64, - 0x75, 0x6c, 0x65, 0x73, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xb0, 0x01, 0x0a, - 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x64, 0x2e, 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x06, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, - 0x65, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, - 0xa6, 0x03, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x6c, - 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, - 0x67, 0x73, 0x12, 0x4c, 0x0a, 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, - 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x6d, - 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x11, 0x74, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, + 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, + 0x08, 0x0b, 0x10, 0x0c, 0x4a, 0x04, 0x08, 0x0c, 0x10, 0x0d, 0x1a, 0x91, 0x01, 0x0a, 0x0e, 0x54, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x31, 0x0a, + 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x4c, 0x0a, 0x14, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, - 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, + 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x75, 0x73, 0x65, 0x72, - 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x16, - 0x0a, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, - 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x12, 0x58, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x57, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x61, 0x67, 0x73, - 0x1a, 0x40, 0x0a, 0x12, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x61, 0x67, - 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, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x7a, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, - 0x08, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x08, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, - 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, - 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x4a, 0x04, - 0x08, 0x02, 0x10, 0x03, 0x22, 0x4a, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, - 0x6f, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, - 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, - 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, 0x74, - 0x22, 0x68, 0x0a, 0x13, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x64, 0x69, - 0x74, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, - 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x06, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 0x22, 0x0f, 0x0a, 0x0d, 0x43, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x22, 0x64, 0x0a, 0x0b, 0x46, - 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x69, - 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, - 0x65, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, - 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, - 0x65, 0x2a, 0x34, 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, - 0x0a, 0x12, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x5f, 0x44, 0x41, - 0x45, 0x4d, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, - 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x10, 0x01, 0x32, 0xc9, 0x04, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x41, 0x0a, - 0x0a, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x13, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, - 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x22, 0x03, 0x88, 0x02, 0x01, - 0x12, 0x52, 0x0a, 0x14, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x4a, 0x6f, 0x62, 0x57, 0x69, - 0x74, 0x68, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x63, - 0x71, 0x75, 0x69, 0x72, 0x65, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x1a, 0xe3, + 0x01, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, + 0x6e, 0x12, 0x53, 0x0a, 0x15, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, + 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x13, 0x72, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, + 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, + 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, + 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x04, + 0x08, 0x01, 0x10, 0x02, 0x1a, 0x40, 0x0a, 0x12, 0x54, 0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 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, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xd4, + 0x03, 0x0a, 0x09, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, + 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, + 0x62, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x51, 0x0a, 0x0f, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x64, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x57, 0x6f, 0x72, 0x6b, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x00, 0x52, 0x0e, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x51, 0x0a, 0x0f, + 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x54, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x00, 0x52, + 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, + 0x52, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x72, 0x79, 0x5f, + 0x72, 0x75, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, + 0x6f, 0x62, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, + 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, + 0x52, 0x75, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, + 0x64, 0x65, 0x1a, 0x55, 0x0a, 0x0e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, + 0x75, 0x69, 0x6c, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2d, 0x0a, 0x07, 0x74, 0x69, + 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, + 0x52, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x1a, 0x10, 0x0a, 0x0e, 0x54, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x1a, 0x10, 0x0a, 0x0e, 0x54, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x42, 0x06, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x89, 0x0b, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x54, 0x0a, + 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, + 0x6f, 0x62, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x48, 0x00, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, + 0x69, 0x6c, 0x64, 0x12, 0x54, 0x0a, 0x0f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, + 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x55, 0x0a, 0x10, 0x74, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, + 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x48, 0x00, + 0x52, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, + 0x1a, 0xc0, 0x02, 0x0a, 0x0e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, + 0x69, 0x6c, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x2d, + 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x69, + 0x6d, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x2d, 0x0a, + 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x6f, 0x64, + 0x75, 0x6c, 0x65, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x55, 0x0a, 0x15, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x14, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x08, 0x61, 0x69, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x49, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x07, 0x61, 0x69, 0x54, 0x61, + 0x73, 0x6b, 0x73, 0x1a, 0x9d, 0x05, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x3e, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3c, 0x0a, 0x0e, 0x73, 0x74, 0x6f, 0x70, 0x5f, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0d, 0x73, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, + 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0e, 0x72, 0x69, 0x63, 0x68, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x41, 0x0a, 0x1d, 0x65, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x1a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x61, 0x0a, 0x17, + 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, + 0x38, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, + 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x0c, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x65, 0x73, 0x65, 0x74, 0x52, + 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x21, 0x0a, 0x0c, + 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, + 0x2a, 0x0a, 0x11, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, + 0x68, 0x61, 0x73, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x6d, 0x6f, 0x64, 0x75, + 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x48, 0x61, 0x73, 0x68, 0x12, 0x20, 0x0a, 0x0c, 0x68, + 0x61, 0x73, 0x5f, 0x61, 0x69, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0a, 0x68, 0x61, 0x73, 0x41, 0x69, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x2e, 0x0a, + 0x13, 0x68, 0x61, 0x73, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x68, 0x61, 0x73, 0x45, + 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x4a, 0x04, 0x08, + 0x07, 0x10, 0x08, 0x1a, 0x74, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, + 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, + 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x6d, 0x6f, + 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, + 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x22, 0xb0, 0x01, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x6c, 0x65, + 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, + 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x22, 0xa6, 0x03, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, + 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, + 0x12, 0x25, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x4c, 0x6f, + 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x4c, 0x0a, 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, + 0x6c, 0x65, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, + 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x4c, 0x0a, 0x14, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x76, 0x61, + 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x12, 0x75, 0x73, 0x65, 0x72, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x12, 0x58, 0x0a, 0x0e, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x07, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x61, 0x67, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x54, 0x61, 0x67, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x54, 0x61, 0x67, 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, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x7a, 0x0a, + 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x43, + 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0x4a, 0x0a, 0x12, 0x43, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, + 0x63, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, + 0x79, 0x43, 0x6f, 0x73, 0x74, 0x22, 0x68, 0x0a, 0x13, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, + 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, + 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x12, 0x29, 0x0a, 0x10, + 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x43, + 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x64, 0x67, 0x65, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 0x22, + 0x0f, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x22, 0x64, 0x0a, 0x0b, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x17, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x44, 0x61, 0x74, 0x61, + 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x2a, 0x34, 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, + 0x45, 0x52, 0x5f, 0x44, 0x41, 0x45, 0x4d, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, + 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x10, 0x01, 0x32, 0xc9, 0x04, 0x0a, + 0x11, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x65, 0x6d, + 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x0a, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x4a, 0x6f, 0x62, + 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, - 0x28, 0x01, 0x30, 0x01, 0x12, 0x52, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, - 0x6f, 0x74, 0x61, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x07, 0x46, 0x61, 0x69, 0x6c, 0x4a, 0x6f, - 0x62, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, - 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, - 0x3e, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1a, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, - 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, - 0x3c, 0x0a, 0x0a, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x17, 0x2e, + 0x22, 0x03, 0x88, 0x02, 0x01, 0x12, 0x52, 0x0a, 0x14, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x4a, 0x6f, 0x62, 0x57, 0x69, 0x74, 0x68, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x1b, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, + 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x28, 0x01, 0x30, 0x01, 0x12, 0x52, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, + 0x6f, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, + 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, + 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x07, 0x46, + 0x61, 0x69, 0x6c, 0x4a, 0x6f, 0x62, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x1a, + 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, + 0x4a, 0x6f, 0x62, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x1a, + 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3c, 0x0a, 0x0a, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, + 0x6c, 0x65, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x1a, 0x13, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x28, 0x01, 0x12, 0x44, 0x0a, 0x0c, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, + 0x6c, 0x65, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x64, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x6c, 0x65, - 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, 0x12, 0x44, 0x0a, - 0x0c, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x19, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, 0x69, 0x6c, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, - 0x64, 0x30, 0x01, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, - 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x30, 0x01, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1944,16 +1929,15 @@ var file_provisionerd_proto_provisionerd_proto_goTypes = []interface{}{ (*proto.RichParameterValue)(nil), // 27: provisioner.RichParameterValue (*proto.ExternalAuthProvider)(nil), // 28: provisioner.ExternalAuthProvider (*proto.Metadata)(nil), // 29: provisioner.Metadata - (*proto.UserSecretValue)(nil), // 30: provisioner.UserSecretValue - (*proto.Timing)(nil), // 31: provisioner.Timing - (*proto.Resource)(nil), // 32: provisioner.Resource - (*proto.Module)(nil), // 33: provisioner.Module - (*proto.ResourceReplacement)(nil), // 34: provisioner.ResourceReplacement - (*proto.AITask)(nil), // 35: provisioner.AITask - (*proto.RichParameter)(nil), // 36: provisioner.RichParameter - (*proto.ExternalAuthProviderResource)(nil), // 37: provisioner.ExternalAuthProviderResource - (*proto.Preset)(nil), // 38: provisioner.Preset - (*proto.FileUpload)(nil), // 39: provisioner.FileUpload + (*proto.Timing)(nil), // 30: provisioner.Timing + (*proto.Resource)(nil), // 31: provisioner.Resource + (*proto.Module)(nil), // 32: provisioner.Module + (*proto.ResourceReplacement)(nil), // 33: provisioner.ResourceReplacement + (*proto.AITask)(nil), // 34: provisioner.AITask + (*proto.RichParameter)(nil), // 35: provisioner.RichParameter + (*proto.ExternalAuthProviderResource)(nil), // 36: provisioner.ExternalAuthProviderResource + (*proto.Preset)(nil), // 37: provisioner.Preset + (*proto.FileUpload)(nil), // 38: provisioner.FileUpload } var file_provisionerd_proto_provisionerd_proto_depIdxs = []int32{ 12, // 0: provisionerd.AcquiredJob.workspace_build:type_name -> provisionerd.AcquiredJob.WorkspaceBuild @@ -1979,47 +1963,46 @@ var file_provisionerd_proto_provisionerd_proto_depIdxs = []int32{ 28, // 20: provisionerd.AcquiredJob.WorkspaceBuild.external_auth_providers:type_name -> provisioner.ExternalAuthProvider 29, // 21: provisionerd.AcquiredJob.WorkspaceBuild.metadata:type_name -> provisioner.Metadata 27, // 22: provisionerd.AcquiredJob.WorkspaceBuild.previous_parameter_values:type_name -> provisioner.RichParameterValue - 30, // 23: provisionerd.AcquiredJob.WorkspaceBuild.user_secrets:type_name -> provisioner.UserSecretValue - 29, // 24: provisionerd.AcquiredJob.TemplateImport.metadata:type_name -> provisioner.Metadata - 25, // 25: provisionerd.AcquiredJob.TemplateImport.user_variable_values:type_name -> provisioner.VariableValue - 27, // 26: provisionerd.AcquiredJob.TemplateDryRun.rich_parameter_values:type_name -> provisioner.RichParameterValue - 25, // 27: provisionerd.AcquiredJob.TemplateDryRun.variable_values:type_name -> provisioner.VariableValue - 29, // 28: provisionerd.AcquiredJob.TemplateDryRun.metadata:type_name -> provisioner.Metadata - 31, // 29: provisionerd.FailedJob.WorkspaceBuild.timings:type_name -> provisioner.Timing - 32, // 30: provisionerd.CompletedJob.WorkspaceBuild.resources:type_name -> provisioner.Resource - 31, // 31: provisionerd.CompletedJob.WorkspaceBuild.timings:type_name -> provisioner.Timing - 33, // 32: provisionerd.CompletedJob.WorkspaceBuild.modules:type_name -> provisioner.Module - 34, // 33: provisionerd.CompletedJob.WorkspaceBuild.resource_replacements:type_name -> provisioner.ResourceReplacement - 35, // 34: provisionerd.CompletedJob.WorkspaceBuild.ai_tasks:type_name -> provisioner.AITask - 32, // 35: provisionerd.CompletedJob.TemplateImport.start_resources:type_name -> provisioner.Resource - 32, // 36: provisionerd.CompletedJob.TemplateImport.stop_resources:type_name -> provisioner.Resource - 36, // 37: provisionerd.CompletedJob.TemplateImport.rich_parameters:type_name -> provisioner.RichParameter - 37, // 38: provisionerd.CompletedJob.TemplateImport.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource - 33, // 39: provisionerd.CompletedJob.TemplateImport.start_modules:type_name -> provisioner.Module - 38, // 40: provisionerd.CompletedJob.TemplateImport.presets:type_name -> provisioner.Preset - 32, // 41: provisionerd.CompletedJob.TemplateDryRun.resources:type_name -> provisioner.Resource - 33, // 42: provisionerd.CompletedJob.TemplateDryRun.modules:type_name -> provisioner.Module - 1, // 43: provisionerd.ProvisionerDaemon.AcquireJob:input_type -> provisionerd.Empty - 10, // 44: provisionerd.ProvisionerDaemon.AcquireJobWithCancel:input_type -> provisionerd.CancelAcquire - 8, // 45: provisionerd.ProvisionerDaemon.CommitQuota:input_type -> provisionerd.CommitQuotaRequest - 6, // 46: provisionerd.ProvisionerDaemon.UpdateJob:input_type -> provisionerd.UpdateJobRequest - 3, // 47: provisionerd.ProvisionerDaemon.FailJob:input_type -> provisionerd.FailedJob - 4, // 48: provisionerd.ProvisionerDaemon.CompleteJob:input_type -> provisionerd.CompletedJob - 39, // 49: provisionerd.ProvisionerDaemon.UploadFile:input_type -> provisioner.FileUpload - 11, // 50: provisionerd.ProvisionerDaemon.DownloadFile:input_type -> provisionerd.FileRequest - 2, // 51: provisionerd.ProvisionerDaemon.AcquireJob:output_type -> provisionerd.AcquiredJob - 2, // 52: provisionerd.ProvisionerDaemon.AcquireJobWithCancel:output_type -> provisionerd.AcquiredJob - 9, // 53: provisionerd.ProvisionerDaemon.CommitQuota:output_type -> provisionerd.CommitQuotaResponse - 7, // 54: provisionerd.ProvisionerDaemon.UpdateJob:output_type -> provisionerd.UpdateJobResponse - 1, // 55: provisionerd.ProvisionerDaemon.FailJob:output_type -> provisionerd.Empty - 1, // 56: provisionerd.ProvisionerDaemon.CompleteJob:output_type -> provisionerd.Empty - 1, // 57: provisionerd.ProvisionerDaemon.UploadFile:output_type -> provisionerd.Empty - 39, // 58: provisionerd.ProvisionerDaemon.DownloadFile:output_type -> provisioner.FileUpload - 51, // [51:59] is the sub-list for method output_type - 43, // [43:51] is the sub-list for method input_type - 43, // [43:43] is the sub-list for extension type_name - 43, // [43:43] is the sub-list for extension extendee - 0, // [0:43] is the sub-list for field type_name + 29, // 23: provisionerd.AcquiredJob.TemplateImport.metadata:type_name -> provisioner.Metadata + 25, // 24: provisionerd.AcquiredJob.TemplateImport.user_variable_values:type_name -> provisioner.VariableValue + 27, // 25: provisionerd.AcquiredJob.TemplateDryRun.rich_parameter_values:type_name -> provisioner.RichParameterValue + 25, // 26: provisionerd.AcquiredJob.TemplateDryRun.variable_values:type_name -> provisioner.VariableValue + 29, // 27: provisionerd.AcquiredJob.TemplateDryRun.metadata:type_name -> provisioner.Metadata + 30, // 28: provisionerd.FailedJob.WorkspaceBuild.timings:type_name -> provisioner.Timing + 31, // 29: provisionerd.CompletedJob.WorkspaceBuild.resources:type_name -> provisioner.Resource + 30, // 30: provisionerd.CompletedJob.WorkspaceBuild.timings:type_name -> provisioner.Timing + 32, // 31: provisionerd.CompletedJob.WorkspaceBuild.modules:type_name -> provisioner.Module + 33, // 32: provisionerd.CompletedJob.WorkspaceBuild.resource_replacements:type_name -> provisioner.ResourceReplacement + 34, // 33: provisionerd.CompletedJob.WorkspaceBuild.ai_tasks:type_name -> provisioner.AITask + 31, // 34: provisionerd.CompletedJob.TemplateImport.start_resources:type_name -> provisioner.Resource + 31, // 35: provisionerd.CompletedJob.TemplateImport.stop_resources:type_name -> provisioner.Resource + 35, // 36: provisionerd.CompletedJob.TemplateImport.rich_parameters:type_name -> provisioner.RichParameter + 36, // 37: provisionerd.CompletedJob.TemplateImport.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource + 32, // 38: provisionerd.CompletedJob.TemplateImport.start_modules:type_name -> provisioner.Module + 37, // 39: provisionerd.CompletedJob.TemplateImport.presets:type_name -> provisioner.Preset + 31, // 40: provisionerd.CompletedJob.TemplateDryRun.resources:type_name -> provisioner.Resource + 32, // 41: provisionerd.CompletedJob.TemplateDryRun.modules:type_name -> provisioner.Module + 1, // 42: provisionerd.ProvisionerDaemon.AcquireJob:input_type -> provisionerd.Empty + 10, // 43: provisionerd.ProvisionerDaemon.AcquireJobWithCancel:input_type -> provisionerd.CancelAcquire + 8, // 44: provisionerd.ProvisionerDaemon.CommitQuota:input_type -> provisionerd.CommitQuotaRequest + 6, // 45: provisionerd.ProvisionerDaemon.UpdateJob:input_type -> provisionerd.UpdateJobRequest + 3, // 46: provisionerd.ProvisionerDaemon.FailJob:input_type -> provisionerd.FailedJob + 4, // 47: provisionerd.ProvisionerDaemon.CompleteJob:input_type -> provisionerd.CompletedJob + 38, // 48: provisionerd.ProvisionerDaemon.UploadFile:input_type -> provisioner.FileUpload + 11, // 49: provisionerd.ProvisionerDaemon.DownloadFile:input_type -> provisionerd.FileRequest + 2, // 50: provisionerd.ProvisionerDaemon.AcquireJob:output_type -> provisionerd.AcquiredJob + 2, // 51: provisionerd.ProvisionerDaemon.AcquireJobWithCancel:output_type -> provisionerd.AcquiredJob + 9, // 52: provisionerd.ProvisionerDaemon.CommitQuota:output_type -> provisionerd.CommitQuotaResponse + 7, // 53: provisionerd.ProvisionerDaemon.UpdateJob:output_type -> provisionerd.UpdateJobResponse + 1, // 54: provisionerd.ProvisionerDaemon.FailJob:output_type -> provisionerd.Empty + 1, // 55: provisionerd.ProvisionerDaemon.CompleteJob:output_type -> provisionerd.Empty + 1, // 56: provisionerd.ProvisionerDaemon.UploadFile:output_type -> provisionerd.Empty + 38, // 57: provisionerd.ProvisionerDaemon.DownloadFile:output_type -> provisioner.FileUpload + 50, // [50:58] is the sub-list for method output_type + 42, // [42:50] is the sub-list for method input_type + 42, // [42:42] is the sub-list for extension type_name + 42, // [42:42] is the sub-list for extension extendee + 0, // [0:42] is the sub-list for field type_name } func init() { file_provisionerd_proto_provisionerd_proto_init() } diff --git a/provisionerd/proto/provisionerd.proto b/provisionerd/proto/provisionerd.proto index b258a43400..babc87b39a 100644 --- a/provisionerd/proto/provisionerd.proto +++ b/provisionerd/proto/provisionerd.proto @@ -28,10 +28,9 @@ message AcquiredJob { repeated provisioner.RichParameterValue previous_parameter_values = 10; // Reserved 11 for an experiment `exp_reuse_terraform_workspace` (bool) that was replaced. reserved 11; - // User secrets belonging to the workspace owner, to be forwarded into the - // plan request sent to the provisioner. Only populated for start - // transitions. - repeated provisioner.UserSecretValue user_secrets = 12; + // Reserved 12 for `user_secrets` introduced in v1.17 (#24542) and removed + // in v1.18 along with the rest of the `coder_secret` Terraform integration. + reserved 12; } message TemplateImport { provisioner.Metadata metadata = 1; diff --git a/provisionerd/proto/version.go b/provisionerd/proto/version.go index f9248cb878..48cb2fc8eb 100644 --- a/provisionerd/proto/version.go +++ b/provisionerd/proto/version.go @@ -85,9 +85,16 @@ import "github.com/coder/coder/v2/apiversion" // - Added `UserSecretValue` message and `user_secrets` field to `PlanRequest`, // carrying user secret values from provisioner daemons to provisioners // during plan. +// +// API v1.18: +// - Removed `user_secrets` from `AcquiredJob.WorkspaceBuild` (field 12) and +// `PlanRequest` (field 7), along with the `UserSecretValue` message. The +// `coder_secret` Terraform integration is being removed; user secrets are +// still delivered to running workspaces via the agent manifest path, which +// is independent of this proto. const ( CurrentMajor = 1 - CurrentMinor = 17 + CurrentMinor = 18 ) // CurrentVersion is the current provisionerd API version. diff --git a/provisionerd/runner/runner.go b/provisionerd/runner/runner.go index 0ba7fcba2d..f287880f97 100644 --- a/provisionerd/runner/runner.go +++ b/provisionerd/runner/runner.go @@ -964,7 +964,6 @@ func (r *Runner) runWorkspaceBuild(ctx context.Context) (*proto.CompletedJob, *p ExternalAuthProviders: r.job.GetWorkspaceBuild().ExternalAuthProviders, PreviousParameterValues: r.job.GetWorkspaceBuild().PreviousParameterValues, State: r.job.GetWorkspaceBuild().State, - UserSecrets: r.job.GetWorkspaceBuild().UserSecrets, }) if failed != nil { return nil, failed diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index 4075fadc4e..c8091fcf97 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -3582,86 +3582,6 @@ func (x *InitComplete) GetModuleFilesHash() []byte { return nil } -// UserSecretValue carries a single user secret to a provisioner. env_name and -// file_path describe the bindings the user requested when creating the secret. -// The terraform provisioner exposes secrets via CODER_SECRET_ENV_* and -// CODER_SECRET_FILE_* environment variables consumed by terraform-provider-coder's -// coder_secret data source -type UserSecretValue struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Environment variable name the user selected (e.g. "GITHUB_TOKEN"). Intended - // to be treated as an opaque lookup key, i.e. consumers must preserve it - // verbatim when matching against a data.coder_secret.env_name attribute. - // Consumers can assume names are POSIX-compliant. Optional: env_name and - // file_path are independent. - EnvName string `protobuf:"bytes,1,opt,name=env_name,json=envName,proto3" json:"env_name,omitempty"` - // Filesystem path the user requested this secret be bound to (e.g. "~/creds" - // or "/etc/creds"). This path is not expanded. Expansion happens only where - // the secret is actually materialized on disk. Intended to be treated as an - // opaque lookup key, i.e. consumers must preserve it verbatim when matching - // against a data.coder_secret.file attribute. Optional; env_name and - // file_path are independent. - FilePath string `protobuf:"bytes,2,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"` - // Secret value, which may be arbitrary binary data. - Value []byte `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` -} - -func (x *UserSecretValue) Reset() { - *x = UserSecretValue{} - if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[39] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *UserSecretValue) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*UserSecretValue) ProtoMessage() {} - -func (x *UserSecretValue) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[39] - 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 UserSecretValue.ProtoReflect.Descriptor instead. -func (*UserSecretValue) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{39} -} - -func (x *UserSecretValue) GetEnvName() string { - if x != nil { - return x.EnvName - } - return "" -} - -func (x *UserSecretValue) GetFilePath() string { - if x != nil { - return x.FilePath - } - return "" -} - -func (x *UserSecretValue) GetValue() []byte { - if x != nil { - return x.Value - } - return nil -} - // PlanRequest asks the provisioner to plan what resources & parameters it will create type PlanRequest struct { state protoimpl.MessageState @@ -3675,17 +3595,12 @@ type PlanRequest struct { PreviousParameterValues []*RichParameterValue `protobuf:"bytes,5,rep,name=previous_parameter_values,json=previousParameterValues,proto3" json:"previous_parameter_values,omitempty"` // state is the provisioner state (if any) State []byte `protobuf:"bytes,6,opt,name=state,proto3" json:"state,omitempty"` - // User secrets to make available during plan. Not carried on ApplyRequest - // because plan evaluates data.coder_secret references and bakes the - // resolved values into plan state, so apply does not need the raw secrets. - // Provisioner-specific handling is documented on the UserSecretValue message. - UserSecrets []*UserSecretValue `protobuf:"bytes,7,rep,name=user_secrets,json=userSecrets,proto3" json:"user_secrets,omitempty"` } func (x *PlanRequest) Reset() { *x = PlanRequest{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[40] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3698,7 +3613,7 @@ func (x *PlanRequest) String() string { func (*PlanRequest) ProtoMessage() {} func (x *PlanRequest) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[40] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3711,7 +3626,7 @@ func (x *PlanRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PlanRequest.ProtoReflect.Descriptor instead. func (*PlanRequest) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{40} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{39} } func (x *PlanRequest) GetMetadata() *Metadata { @@ -3756,13 +3671,6 @@ func (x *PlanRequest) GetState() []byte { return nil } -func (x *PlanRequest) GetUserSecrets() []*UserSecretValue { - if x != nil { - return x.UserSecrets - } - return nil -} - // PlanComplete indicates a request to plan completed. type PlanComplete struct { state protoimpl.MessageState @@ -3780,7 +3688,7 @@ type PlanComplete struct { func (x *PlanComplete) Reset() { *x = PlanComplete{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[41] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3793,7 +3701,7 @@ func (x *PlanComplete) String() string { func (*PlanComplete) ProtoMessage() {} func (x *PlanComplete) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[41] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3806,7 +3714,7 @@ func (x *PlanComplete) ProtoReflect() protoreflect.Message { // Deprecated: Use PlanComplete.ProtoReflect.Descriptor instead. func (*PlanComplete) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{41} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{40} } func (x *PlanComplete) GetError() string { @@ -3864,7 +3772,7 @@ type ApplyRequest struct { func (x *ApplyRequest) Reset() { *x = ApplyRequest{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[42] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3877,7 +3785,7 @@ func (x *ApplyRequest) String() string { func (*ApplyRequest) ProtoMessage() {} func (x *ApplyRequest) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[42] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3890,7 +3798,7 @@ func (x *ApplyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyRequest.ProtoReflect.Descriptor instead. func (*ApplyRequest) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{42} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{41} } func (x *ApplyRequest) GetMetadata() *Metadata { @@ -3914,7 +3822,7 @@ type ApplyComplete struct { func (x *ApplyComplete) Reset() { *x = ApplyComplete{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[43] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3927,7 +3835,7 @@ func (x *ApplyComplete) String() string { func (*ApplyComplete) ProtoMessage() {} func (x *ApplyComplete) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[43] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3940,7 +3848,7 @@ func (x *ApplyComplete) ProtoReflect() protoreflect.Message { // Deprecated: Use ApplyComplete.ProtoReflect.Descriptor instead. func (*ApplyComplete) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{43} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{42} } func (x *ApplyComplete) GetState() []byte { @@ -3976,7 +3884,7 @@ type GraphRequest struct { func (x *GraphRequest) Reset() { *x = GraphRequest{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[44] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3989,7 +3897,7 @@ func (x *GraphRequest) String() string { func (*GraphRequest) ProtoMessage() {} func (x *GraphRequest) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[44] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[43] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4002,7 +3910,7 @@ func (x *GraphRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GraphRequest.ProtoReflect.Descriptor instead. func (*GraphRequest) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{44} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{43} } func (x *GraphRequest) GetMetadata() *Metadata { @@ -4040,7 +3948,7 @@ type GraphComplete struct { func (x *GraphComplete) Reset() { *x = GraphComplete{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[45] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4053,7 +3961,7 @@ func (x *GraphComplete) String() string { func (*GraphComplete) ProtoMessage() {} func (x *GraphComplete) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[45] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4066,7 +3974,7 @@ func (x *GraphComplete) ProtoReflect() protoreflect.Message { // Deprecated: Use GraphComplete.ProtoReflect.Descriptor instead. func (*GraphComplete) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{45} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{44} } func (x *GraphComplete) GetError() string { @@ -4149,7 +4057,7 @@ type Timing struct { func (x *Timing) Reset() { *x = Timing{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[46] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4162,7 +4070,7 @@ func (x *Timing) String() string { func (*Timing) ProtoMessage() {} func (x *Timing) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[46] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4175,7 +4083,7 @@ func (x *Timing) ProtoReflect() protoreflect.Message { // Deprecated: Use Timing.ProtoReflect.Descriptor instead. func (*Timing) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{46} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{45} } func (x *Timing) GetStart() *timestamppb.Timestamp { @@ -4237,7 +4145,7 @@ type CancelRequest struct { func (x *CancelRequest) Reset() { *x = CancelRequest{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[47] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4250,7 +4158,7 @@ func (x *CancelRequest) String() string { func (*CancelRequest) ProtoMessage() {} func (x *CancelRequest) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[47] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4263,7 +4171,7 @@ func (x *CancelRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CancelRequest.ProtoReflect.Descriptor instead. func (*CancelRequest) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{47} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{46} } type Request struct { @@ -4287,7 +4195,7 @@ type Request struct { func (x *Request) Reset() { *x = Request{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[48] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4300,7 +4208,7 @@ func (x *Request) String() string { func (*Request) ProtoMessage() {} func (x *Request) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[48] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4313,7 +4221,7 @@ func (x *Request) ProtoReflect() protoreflect.Message { // Deprecated: Use Request.ProtoReflect.Descriptor instead. func (*Request) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{48} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{47} } func (m *Request) GetType() isRequest_Type { @@ -4456,7 +4364,7 @@ type Response struct { func (x *Response) Reset() { *x = Response{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[49] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4469,7 +4377,7 @@ func (x *Response) String() string { func (*Response) ProtoMessage() {} func (x *Response) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[49] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4482,7 +4390,7 @@ func (x *Response) ProtoReflect() protoreflect.Message { // Deprecated: Use Response.ProtoReflect.Descriptor instead. func (*Response) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{49} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{48} } func (m *Response) GetType() isResponse_Type { @@ -4616,7 +4524,7 @@ type FileUpload struct { func (x *FileUpload) Reset() { *x = FileUpload{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[50] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4629,7 +4537,7 @@ func (x *FileUpload) String() string { func (*FileUpload) ProtoMessage() {} func (x *FileUpload) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[50] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4642,7 +4550,7 @@ func (x *FileUpload) ProtoReflect() protoreflect.Message { // Deprecated: Use FileUpload.ProtoReflect.Descriptor instead. func (*FileUpload) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{50} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{49} } func (m *FileUpload) GetType() isFileUpload_Type { @@ -4706,7 +4614,7 @@ type FailedFile struct { func (x *FailedFile) Reset() { *x = FailedFile{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[51] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4719,7 +4627,7 @@ func (x *FailedFile) String() string { func (*FailedFile) ProtoMessage() {} func (x *FailedFile) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[51] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4732,7 +4640,7 @@ func (x *FailedFile) ProtoReflect() protoreflect.Message { // Deprecated: Use FailedFile.ProtoReflect.Descriptor instead. func (*FailedFile) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{51} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{50} } func (x *FailedFile) GetError() string { @@ -4760,7 +4668,7 @@ type DataUpload struct { func (x *DataUpload) Reset() { *x = DataUpload{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[52] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4773,7 +4681,7 @@ func (x *DataUpload) String() string { func (*DataUpload) ProtoMessage() {} func (x *DataUpload) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[52] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4786,7 +4694,7 @@ func (x *DataUpload) ProtoReflect() protoreflect.Message { // Deprecated: Use DataUpload.ProtoReflect.Descriptor instead. func (*DataUpload) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{52} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{51} } func (x *DataUpload) GetUploadType() DataUploadType { @@ -4833,7 +4741,7 @@ type ChunkPiece struct { func (x *ChunkPiece) Reset() { *x = ChunkPiece{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[53] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4846,7 +4754,7 @@ func (x *ChunkPiece) String() string { func (*ChunkPiece) ProtoMessage() {} func (x *ChunkPiece) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[53] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4859,7 +4767,7 @@ func (x *ChunkPiece) ProtoReflect() protoreflect.Message { // Deprecated: Use ChunkPiece.ProtoReflect.Descriptor instead. func (*ChunkPiece) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{53} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{52} } func (x *ChunkPiece) GetData() []byte { @@ -4899,7 +4807,7 @@ type Agent_Metadata struct { func (x *Agent_Metadata) Reset() { *x = Agent_Metadata{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[54] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4912,7 +4820,7 @@ func (x *Agent_Metadata) String() string { func (*Agent_Metadata) ProtoMessage() {} func (x *Agent_Metadata) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[54] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4984,7 +4892,7 @@ type Resource_Metadata struct { func (x *Resource_Metadata) Reset() { *x = Resource_Metadata{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[56] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4997,7 +4905,7 @@ func (x *Resource_Metadata) String() string { func (*Resource_Metadata) ProtoMessage() {} func (x *Resource_Metadata) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[56] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5558,259 +5466,249 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x52, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, - 0x46, 0x69, 0x6c, 0x65, 0x73, 0x48, 0x61, 0x73, 0x68, 0x22, 0x5f, 0x0a, 0x0f, 0x55, 0x73, 0x65, - 0x72, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x19, 0x0a, 0x08, - 0x65, 0x6e, 0x76, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, - 0x65, 0x6e, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, - 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, - 0x50, 0x61, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xe9, 0x03, 0x0a, 0x0b, 0x50, - 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x53, 0x0a, - 0x15, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, - 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, - 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, - 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x59, 0x0a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, - 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x15, 0x65, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x73, 0x12, 0x5b, 0x0a, 0x19, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, - 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x17, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, - 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3f, 0x0a, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x73, 0x65, - 0x63, 0x72, 0x65, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, - 0x63, 0x72, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x53, - 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x22, 0x80, 0x02, 0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x6e, 0x43, - 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2d, 0x0a, - 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, - 0x69, 0x6e, 0x67, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x12, 0x0a, 0x04, - 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, - 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x55, - 0x0a, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x61, - 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, - 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x69, 0x5f, 0x74, 0x61, 0x73, 0x6b, - 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x61, 0x69, - 0x54, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x41, 0x0a, 0x0c, 0x41, 0x70, 0x70, - 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, + 0x46, 0x69, 0x6c, 0x65, 0x73, 0x48, 0x61, 0x73, 0x68, 0x22, 0xae, 0x03, 0x0a, 0x0b, 0x50, 0x6c, + 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x6a, 0x0a, 0x0d, - 0x41, 0x70, 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, + 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x53, 0x0a, 0x15, + 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, 0x69, + 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, + 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x59, 0x0a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, + 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x73, 0x12, 0x5b, 0x0a, 0x19, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x70, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x17, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x22, 0x80, 0x02, 0x0a, 0x0c, 0x50, + 0x6c, 0x61, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x12, 0x2d, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, + 0x73, 0x74, 0x12, 0x55, 0x0a, 0x15, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, + 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x52, 0x14, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x70, + 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x69, 0x5f, + 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0b, 0x61, 0x69, 0x54, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x41, 0x0a, + 0x0c, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, + 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x22, 0x6a, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2d, 0x0a, + 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, + 0x69, 0x6e, 0x67, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x73, 0x0a, 0x0c, + 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, + 0x30, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x47, 0x72, + 0x61, 0x70, 0x68, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x22, 0xd9, 0x03, 0x0a, 0x0d, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2d, 0x0a, 0x07, 0x74, 0x69, 0x6d, - 0x69, 0x6e, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, + 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x52, - 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x73, 0x0a, 0x0c, 0x47, 0x72, 0x61, 0x70, - 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x30, 0x0a, 0x06, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xd9, 0x03, - 0x0a, 0x0d, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2d, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x74, 0x69, 0x6d, - 0x69, 0x6e, 0x67, 0x73, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x61, 0x72, - 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, - 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x61, 0x0a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, - 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, - 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x0a, 0x07, 0x70, 0x72, 0x65, 0x73, - 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x65, 0x73, 0x65, 0x74, 0x52, 0x07, - 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x68, 0x61, 0x73, 0x5f, 0x61, - 0x69, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x68, - 0x61, 0x73, 0x41, 0x69, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x2e, 0x0a, 0x08, 0x61, 0x69, 0x5f, - 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x49, 0x54, 0x61, 0x73, 0x6b, - 0x52, 0x07, 0x61, 0x69, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x68, 0x61, 0x73, - 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x68, 0x61, 0x73, 0x45, 0x78, 0x74, 0x65, 0x72, - 0x6e, 0x61, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xfa, 0x01, 0x0a, 0x06, 0x54, 0x69, - 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 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, - 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 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, - 0x03, 0x65, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, - 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x9e, 0x03, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x12, 0x31, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x07, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, + 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x61, 0x0a, 0x17, 0x65, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, + 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, + 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x0a, 0x07, + 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x65, 0x73, + 0x65, 0x74, 0x52, 0x07, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x68, + 0x61, 0x73, 0x5f, 0x61, 0x69, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0a, 0x68, 0x61, 0x73, 0x41, 0x69, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x2e, 0x0a, + 0x08, 0x61, 0x69, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x49, + 0x54, 0x61, 0x73, 0x6b, 0x52, 0x07, 0x61, 0x69, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x2e, 0x0a, + 0x13, 0x68, 0x61, 0x73, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x68, 0x61, 0x73, 0x45, + 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xfa, 0x01, + 0x0a, 0x06, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x18, 0x01, 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, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, + 0x64, 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, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x05, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x43, 0x61, + 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x9e, 0x03, 0x0a, 0x07, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x06, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x31, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x48, 0x00, 0x52, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x69, 0x6e, 0x69, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x48, 0x00, 0x52, 0x04, 0x69, 0x6e, 0x69, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x70, 0x6c, 0x61, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x31, 0x0a, 0x05, 0x61, 0x70, 0x70, + 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x31, 0x0a, 0x05, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, + 0x34, 0x0a, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x61, + 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x63, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x2d, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x00, 0x52, 0x04, + 0x66, 0x69, 0x6c, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xae, 0x03, 0x0a, + 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, + 0x32, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, + 0x73, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x70, 0x61, + 0x72, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x69, 0x6e, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x50, 0x61, 0x72, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, - 0x70, 0x61, 0x72, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x69, 0x6e, 0x69, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, - 0x04, 0x69, 0x6e, 0x69, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, - 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x31, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, - 0x00, 0x52, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x31, 0x0a, 0x05, 0x67, 0x72, 0x61, 0x70, - 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x34, 0x0a, 0x06, 0x63, - 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x12, 0x2d, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x46, 0x69, - 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x00, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, - 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xae, 0x03, 0x0a, 0x08, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x32, 0x0a, 0x05, 0x70, - 0x61, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x6f, - 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x12, - 0x2f, 0x0a, 0x04, 0x69, 0x6e, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x49, 0x6e, 0x69, 0x74, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, 0x69, 0x6e, 0x69, 0x74, - 0x12, 0x2f, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x6c, 0x61, - 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, - 0x6e, 0x12, 0x32, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, - 0x70, 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, - 0x61, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x32, 0x0a, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x06, + 0x49, 0x6e, 0x69, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, + 0x69, 0x6e, 0x69, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, + 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x32, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, - 0x48, 0x00, 0x52, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x3a, 0x0a, 0x0b, 0x64, 0x61, 0x74, - 0x61, 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x44, 0x61, 0x74, - 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x55, - 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3a, 0x0a, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x70, - 0x69, 0x65, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x50, 0x69, - 0x65, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x50, 0x69, 0x65, 0x63, - 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xbd, 0x01, 0x0a, 0x0a, 0x46, 0x69, - 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3a, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, - 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x44, 0x61, 0x74, 0x61, - 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x55, 0x70, - 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3a, 0x0a, 0x0b, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x5f, 0x70, 0x69, - 0x65, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x50, 0x69, 0x65, - 0x63, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x50, 0x69, 0x65, 0x63, 0x65, - 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x46, 0x61, - 0x69, 0x6c, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x22, 0x0a, 0x0a, 0x46, 0x61, 0x69, - 0x6c, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x9c, 0x01, - 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3c, 0x0a, 0x0b, - 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x44, 0x61, 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, - 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x61, - 0x74, 0x61, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x64, - 0x61, 0x74, 0x61, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, - 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, - 0x53, 0x69, 0x7a, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x22, 0x67, 0x0a, 0x0a, - 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x50, 0x69, 0x65, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x24, - 0x0a, 0x0e, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x68, 0x61, 0x73, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x66, 0x75, 0x6c, 0x6c, 0x44, 0x61, 0x74, 0x61, - 0x48, 0x61, 0x73, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x69, 0x65, 0x63, 0x65, 0x5f, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x70, 0x69, 0x65, 0x63, 0x65, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x2a, 0xa8, 0x01, 0x0a, 0x11, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x44, - 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x4f, 0x52, 0x4d, - 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x41, 0x44, 0x49, - 0x4f, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x52, 0x4f, 0x50, 0x44, 0x4f, 0x57, 0x4e, 0x10, - 0x03, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x50, 0x55, 0x54, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, - 0x54, 0x45, 0x58, 0x54, 0x41, 0x52, 0x45, 0x41, 0x10, 0x05, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x4c, - 0x49, 0x44, 0x45, 0x52, 0x10, 0x06, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x42, - 0x4f, 0x58, 0x10, 0x07, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x57, 0x49, 0x54, 0x43, 0x48, 0x10, 0x08, - 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x41, 0x47, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x10, 0x09, 0x12, - 0x0f, 0x0a, 0x0b, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x10, 0x0a, - 0x2a, 0x3f, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, - 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, - 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, - 0x57, 0x41, 0x52, 0x4e, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, - 0x04, 0x2a, 0x3b, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, - 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x00, 0x12, - 0x11, 0x0a, 0x0d, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, - 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x02, 0x2a, 0x35, - 0x0a, 0x09, 0x41, 0x70, 0x70, 0x4f, 0x70, 0x65, 0x6e, 0x49, 0x6e, 0x12, 0x0e, 0x0a, 0x06, 0x57, - 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x10, 0x00, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x53, - 0x4c, 0x49, 0x4d, 0x5f, 0x57, 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, - 0x54, 0x41, 0x42, 0x10, 0x02, 0x2a, 0x37, 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, - 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, - 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f, 0x59, 0x10, 0x02, 0x2a, 0x3e, - 0x0a, 0x1b, 0x50, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x08, 0x0a, - 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x52, 0x45, 0x41, 0x54, - 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x10, 0x02, 0x2a, 0x44, - 0x0a, 0x0b, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, - 0x0e, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, - 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x50, 0x4c, 0x41, 0x4e, - 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x53, 0x54, 0x41, - 0x54, 0x45, 0x10, 0x02, 0x2a, 0x35, 0x0a, 0x0b, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x00, - 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, - 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x2a, 0x47, 0x0a, 0x0e, 0x44, - 0x61, 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, - 0x13, 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x4f, 0x44, 0x55, 0x4c, 0x45, 0x5f, 0x46, 0x49, 0x4c, - 0x45, 0x53, 0x10, 0x01, 0x32, 0x49, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, - 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, - 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, + 0x48, 0x00, 0x52, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x32, 0x0a, 0x05, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x6f, 0x6d, 0x70, + 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x3a, 0x0a, + 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x44, 0x61, 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x00, 0x52, 0x0a, 0x64, + 0x61, 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3a, 0x0a, 0x0b, 0x63, 0x68, 0x75, + 0x6e, 0x6b, 0x5f, 0x70, 0x69, 0x65, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x75, + 0x6e, 0x6b, 0x50, 0x69, 0x65, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, + 0x50, 0x69, 0x65, 0x63, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xbd, 0x01, + 0x0a, 0x0a, 0x46, 0x69, 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3a, 0x0a, 0x0b, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x44, 0x61, 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x61, + 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3a, 0x0a, 0x0b, 0x63, 0x68, 0x75, 0x6e, + 0x6b, 0x5f, 0x70, 0x69, 0x65, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x50, 0x69, 0x65, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x50, + 0x69, 0x65, 0x63, 0x65, 0x12, 0x2f, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x22, 0x0a, + 0x0a, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x22, 0x9c, 0x01, 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, + 0x12, 0x3c, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x0a, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, + 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x66, + 0x69, 0x6c, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, + 0x66, 0x69, 0x6c, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x68, 0x75, 0x6e, + 0x6b, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, + 0x22, 0x67, 0x0a, 0x0a, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x50, 0x69, 0x65, 0x63, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, + 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x66, 0x75, 0x6c, 0x6c, + 0x44, 0x61, 0x74, 0x61, 0x48, 0x61, 0x73, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x69, 0x65, 0x63, + 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x70, + 0x69, 0x65, 0x63, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x2a, 0xa8, 0x01, 0x0a, 0x11, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, + 0x46, 0x4f, 0x52, 0x4d, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, + 0x52, 0x41, 0x44, 0x49, 0x4f, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x52, 0x4f, 0x50, 0x44, + 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x50, 0x55, 0x54, 0x10, 0x04, + 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x45, 0x58, 0x54, 0x41, 0x52, 0x45, 0x41, 0x10, 0x05, 0x12, 0x0a, + 0x0a, 0x06, 0x53, 0x4c, 0x49, 0x44, 0x45, 0x52, 0x10, 0x06, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x48, + 0x45, 0x43, 0x4b, 0x42, 0x4f, 0x58, 0x10, 0x07, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x57, 0x49, 0x54, + 0x43, 0x48, 0x10, 0x08, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x41, 0x47, 0x53, 0x45, 0x4c, 0x45, 0x43, + 0x54, 0x10, 0x09, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x53, 0x45, 0x4c, 0x45, + 0x43, 0x54, 0x10, 0x0a, 0x2a, 0x3f, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, + 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, + 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x02, + 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, 0x4e, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, + 0x52, 0x4f, 0x52, 0x10, 0x04, 0x2a, 0x3b, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, + 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, + 0x52, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, + 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, + 0x10, 0x02, 0x2a, 0x35, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x4f, 0x70, 0x65, 0x6e, 0x49, 0x6e, 0x12, + 0x0e, 0x0a, 0x06, 0x57, 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x10, 0x00, 0x1a, 0x02, 0x08, 0x01, 0x12, + 0x0f, 0x0a, 0x0b, 0x53, 0x4c, 0x49, 0x4d, 0x5f, 0x57, 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x10, 0x01, + 0x12, 0x07, 0x0a, 0x03, 0x54, 0x41, 0x42, 0x10, 0x02, 0x2a, 0x37, 0x0a, 0x13, 0x57, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x53, + 0x54, 0x4f, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f, 0x59, + 0x10, 0x02, 0x2a, 0x3e, 0x0a, 0x1b, 0x50, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x57, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x61, 0x67, + 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, + 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x43, 0x4c, 0x41, 0x49, 0x4d, + 0x10, 0x02, 0x2a, 0x44, 0x0a, 0x0b, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, + 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, + 0x50, 0x4c, 0x41, 0x4e, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x02, 0x2a, 0x35, 0x0a, 0x0b, 0x54, 0x69, 0x6d, 0x69, + 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x54, 0x41, 0x52, 0x54, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, + 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x2a, + 0x47, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x17, 0x0a, 0x13, 0x55, 0x50, 0x4c, 0x4f, 0x41, 0x44, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x55, 0x50, + 0x4c, 0x4f, 0x41, 0x44, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x4f, 0x44, 0x55, 0x4c, 0x45, + 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x10, 0x01, 0x32, 0x49, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, + 0x01, 0x30, 0x01, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, + 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x73, 0x64, 0x6b, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -5826,7 +5724,7 @@ func file_provisionersdk_proto_provisioner_proto_rawDescGZIP() []byte { } var file_provisionersdk_proto_provisioner_proto_enumTypes = make([]protoimpl.EnumInfo, 9) -var file_provisionersdk_proto_provisioner_proto_msgTypes = make([]protoimpl.MessageInfo, 58) +var file_provisionersdk_proto_provisioner_proto_msgTypes = make([]protoimpl.MessageInfo, 57) var file_provisionersdk_proto_provisioner_proto_goTypes = []interface{}{ (ParameterFormType)(0), // 0: provisioner.ParameterFormType (LogLevel)(0), // 1: provisioner.LogLevel @@ -5876,26 +5774,25 @@ var file_provisionersdk_proto_provisioner_proto_goTypes = []interface{}{ (*ParseComplete)(nil), // 45: provisioner.ParseComplete (*InitRequest)(nil), // 46: provisioner.InitRequest (*InitComplete)(nil), // 47: provisioner.InitComplete - (*UserSecretValue)(nil), // 48: provisioner.UserSecretValue - (*PlanRequest)(nil), // 49: provisioner.PlanRequest - (*PlanComplete)(nil), // 50: provisioner.PlanComplete - (*ApplyRequest)(nil), // 51: provisioner.ApplyRequest - (*ApplyComplete)(nil), // 52: provisioner.ApplyComplete - (*GraphRequest)(nil), // 53: provisioner.GraphRequest - (*GraphComplete)(nil), // 54: provisioner.GraphComplete - (*Timing)(nil), // 55: provisioner.Timing - (*CancelRequest)(nil), // 56: provisioner.CancelRequest - (*Request)(nil), // 57: provisioner.Request - (*Response)(nil), // 58: provisioner.Response - (*FileUpload)(nil), // 59: provisioner.FileUpload - (*FailedFile)(nil), // 60: provisioner.FailedFile - (*DataUpload)(nil), // 61: provisioner.DataUpload - (*ChunkPiece)(nil), // 62: provisioner.ChunkPiece - (*Agent_Metadata)(nil), // 63: provisioner.Agent.Metadata - nil, // 64: provisioner.Agent.EnvEntry - (*Resource_Metadata)(nil), // 65: provisioner.Resource.Metadata - nil, // 66: provisioner.ParseComplete.WorkspaceTagsEntry - (*timestamppb.Timestamp)(nil), // 67: google.protobuf.Timestamp + (*PlanRequest)(nil), // 48: provisioner.PlanRequest + (*PlanComplete)(nil), // 49: provisioner.PlanComplete + (*ApplyRequest)(nil), // 50: provisioner.ApplyRequest + (*ApplyComplete)(nil), // 51: provisioner.ApplyComplete + (*GraphRequest)(nil), // 52: provisioner.GraphRequest + (*GraphComplete)(nil), // 53: provisioner.GraphComplete + (*Timing)(nil), // 54: provisioner.Timing + (*CancelRequest)(nil), // 55: provisioner.CancelRequest + (*Request)(nil), // 56: provisioner.Request + (*Response)(nil), // 57: provisioner.Response + (*FileUpload)(nil), // 58: provisioner.FileUpload + (*FailedFile)(nil), // 59: provisioner.FailedFile + (*DataUpload)(nil), // 60: provisioner.DataUpload + (*ChunkPiece)(nil), // 61: provisioner.ChunkPiece + (*Agent_Metadata)(nil), // 62: provisioner.Agent.Metadata + nil, // 63: provisioner.Agent.EnvEntry + (*Resource_Metadata)(nil), // 64: provisioner.Resource.Metadata + nil, // 65: provisioner.ParseComplete.WorkspaceTagsEntry + (*timestamppb.Timestamp)(nil), // 66: google.protobuf.Timestamp } var file_provisionersdk_proto_provisioner_proto_depIdxs = []int32{ 11, // 0: provisioner.RichParameter.options:type_name -> provisioner.RichParameterOption @@ -5906,9 +5803,9 @@ var file_provisionersdk_proto_provisioner_proto_depIdxs = []int32{ 19, // 5: provisioner.Preset.parameters:type_name -> provisioner.PresetParameter 17, // 6: provisioner.Preset.prebuild:type_name -> provisioner.Prebuild 1, // 7: provisioner.Log.level:type_name -> provisioner.LogLevel - 64, // 8: provisioner.Agent.env:type_name -> provisioner.Agent.EnvEntry + 63, // 8: provisioner.Agent.env:type_name -> provisioner.Agent.EnvEntry 34, // 9: provisioner.Agent.apps:type_name -> provisioner.App - 63, // 10: provisioner.Agent.metadata:type_name -> provisioner.Agent.Metadata + 62, // 10: provisioner.Agent.metadata:type_name -> provisioner.Agent.Metadata 30, // 11: provisioner.Agent.display_apps:type_name -> provisioner.DisplayApps 32, // 12: provisioner.Agent.scripts:type_name -> provisioner.Script 31, // 13: provisioner.Agent.extra_envs:type_name -> provisioner.Env @@ -5923,64 +5820,63 @@ var file_provisionersdk_proto_provisioner_proto_depIdxs = []int32{ 2, // 22: provisioner.App.sharing_level:type_name -> provisioner.AppSharingLevel 3, // 23: provisioner.App.open_in:type_name -> provisioner.AppOpenIn 26, // 24: provisioner.Resource.agents:type_name -> provisioner.Agent - 65, // 25: provisioner.Resource.metadata:type_name -> provisioner.Resource.Metadata + 64, // 25: provisioner.Resource.metadata:type_name -> provisioner.Resource.Metadata 40, // 26: provisioner.AITask.sidebar_app:type_name -> provisioner.AITaskSidebarApp 4, // 27: provisioner.Metadata.workspace_transition:type_name -> provisioner.WorkspaceTransition 38, // 28: provisioner.Metadata.workspace_owner_rbac_roles:type_name -> provisioner.Role 5, // 29: provisioner.Metadata.prebuilt_workspace_build_stage:type_name -> provisioner.PrebuiltWorkspaceBuildStage 39, // 30: provisioner.Metadata.running_agent_auth_tokens:type_name -> provisioner.RunningAgentAuthToken 10, // 31: provisioner.ParseComplete.template_variables:type_name -> provisioner.TemplateVariable - 66, // 32: provisioner.ParseComplete.workspace_tags:type_name -> provisioner.ParseComplete.WorkspaceTagsEntry - 55, // 33: provisioner.InitComplete.timings:type_name -> provisioner.Timing + 65, // 32: provisioner.ParseComplete.workspace_tags:type_name -> provisioner.ParseComplete.WorkspaceTagsEntry + 54, // 33: provisioner.InitComplete.timings:type_name -> provisioner.Timing 37, // 34: provisioner.InitComplete.modules:type_name -> provisioner.Module 42, // 35: provisioner.PlanRequest.metadata:type_name -> provisioner.Metadata 13, // 36: provisioner.PlanRequest.rich_parameter_values:type_name -> provisioner.RichParameterValue 21, // 37: provisioner.PlanRequest.variable_values:type_name -> provisioner.VariableValue 25, // 38: provisioner.PlanRequest.external_auth_providers:type_name -> provisioner.ExternalAuthProvider 13, // 39: provisioner.PlanRequest.previous_parameter_values:type_name -> provisioner.RichParameterValue - 48, // 40: provisioner.PlanRequest.user_secrets:type_name -> provisioner.UserSecretValue - 55, // 41: provisioner.PlanComplete.timings:type_name -> provisioner.Timing - 20, // 42: provisioner.PlanComplete.resource_replacements:type_name -> provisioner.ResourceReplacement - 42, // 43: provisioner.ApplyRequest.metadata:type_name -> provisioner.Metadata - 55, // 44: provisioner.ApplyComplete.timings:type_name -> provisioner.Timing - 42, // 45: provisioner.GraphRequest.metadata:type_name -> provisioner.Metadata - 6, // 46: provisioner.GraphRequest.source:type_name -> provisioner.GraphSource - 55, // 47: provisioner.GraphComplete.timings:type_name -> provisioner.Timing - 36, // 48: provisioner.GraphComplete.resources:type_name -> provisioner.Resource - 12, // 49: provisioner.GraphComplete.parameters:type_name -> provisioner.RichParameter - 24, // 50: provisioner.GraphComplete.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource - 18, // 51: provisioner.GraphComplete.presets:type_name -> provisioner.Preset - 41, // 52: provisioner.GraphComplete.ai_tasks:type_name -> provisioner.AITask - 67, // 53: provisioner.Timing.start:type_name -> google.protobuf.Timestamp - 67, // 54: provisioner.Timing.end:type_name -> google.protobuf.Timestamp - 7, // 55: provisioner.Timing.state:type_name -> provisioner.TimingState - 43, // 56: provisioner.Request.config:type_name -> provisioner.Config - 44, // 57: provisioner.Request.parse:type_name -> provisioner.ParseRequest - 46, // 58: provisioner.Request.init:type_name -> provisioner.InitRequest - 49, // 59: provisioner.Request.plan:type_name -> provisioner.PlanRequest - 51, // 60: provisioner.Request.apply:type_name -> provisioner.ApplyRequest - 53, // 61: provisioner.Request.graph:type_name -> provisioner.GraphRequest - 56, // 62: provisioner.Request.cancel:type_name -> provisioner.CancelRequest - 59, // 63: provisioner.Request.file:type_name -> provisioner.FileUpload - 22, // 64: provisioner.Response.log:type_name -> provisioner.Log - 45, // 65: provisioner.Response.parse:type_name -> provisioner.ParseComplete - 47, // 66: provisioner.Response.init:type_name -> provisioner.InitComplete - 50, // 67: provisioner.Response.plan:type_name -> provisioner.PlanComplete - 52, // 68: provisioner.Response.apply:type_name -> provisioner.ApplyComplete - 54, // 69: provisioner.Response.graph:type_name -> provisioner.GraphComplete - 61, // 70: provisioner.Response.data_upload:type_name -> provisioner.DataUpload - 62, // 71: provisioner.Response.chunk_piece:type_name -> provisioner.ChunkPiece - 61, // 72: provisioner.FileUpload.data_upload:type_name -> provisioner.DataUpload - 62, // 73: provisioner.FileUpload.chunk_piece:type_name -> provisioner.ChunkPiece - 60, // 74: provisioner.FileUpload.error:type_name -> provisioner.FailedFile - 8, // 75: provisioner.DataUpload.upload_type:type_name -> provisioner.DataUploadType - 57, // 76: provisioner.Provisioner.Session:input_type -> provisioner.Request - 58, // 77: provisioner.Provisioner.Session:output_type -> provisioner.Response - 77, // [77:78] is the sub-list for method output_type - 76, // [76:77] is the sub-list for method input_type - 76, // [76:76] is the sub-list for extension type_name - 76, // [76:76] is the sub-list for extension extendee - 0, // [0:76] is the sub-list for field type_name + 54, // 40: provisioner.PlanComplete.timings:type_name -> provisioner.Timing + 20, // 41: provisioner.PlanComplete.resource_replacements:type_name -> provisioner.ResourceReplacement + 42, // 42: provisioner.ApplyRequest.metadata:type_name -> provisioner.Metadata + 54, // 43: provisioner.ApplyComplete.timings:type_name -> provisioner.Timing + 42, // 44: provisioner.GraphRequest.metadata:type_name -> provisioner.Metadata + 6, // 45: provisioner.GraphRequest.source:type_name -> provisioner.GraphSource + 54, // 46: provisioner.GraphComplete.timings:type_name -> provisioner.Timing + 36, // 47: provisioner.GraphComplete.resources:type_name -> provisioner.Resource + 12, // 48: provisioner.GraphComplete.parameters:type_name -> provisioner.RichParameter + 24, // 49: provisioner.GraphComplete.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource + 18, // 50: provisioner.GraphComplete.presets:type_name -> provisioner.Preset + 41, // 51: provisioner.GraphComplete.ai_tasks:type_name -> provisioner.AITask + 66, // 52: provisioner.Timing.start:type_name -> google.protobuf.Timestamp + 66, // 53: provisioner.Timing.end:type_name -> google.protobuf.Timestamp + 7, // 54: provisioner.Timing.state:type_name -> provisioner.TimingState + 43, // 55: provisioner.Request.config:type_name -> provisioner.Config + 44, // 56: provisioner.Request.parse:type_name -> provisioner.ParseRequest + 46, // 57: provisioner.Request.init:type_name -> provisioner.InitRequest + 48, // 58: provisioner.Request.plan:type_name -> provisioner.PlanRequest + 50, // 59: provisioner.Request.apply:type_name -> provisioner.ApplyRequest + 52, // 60: provisioner.Request.graph:type_name -> provisioner.GraphRequest + 55, // 61: provisioner.Request.cancel:type_name -> provisioner.CancelRequest + 58, // 62: provisioner.Request.file:type_name -> provisioner.FileUpload + 22, // 63: provisioner.Response.log:type_name -> provisioner.Log + 45, // 64: provisioner.Response.parse:type_name -> provisioner.ParseComplete + 47, // 65: provisioner.Response.init:type_name -> provisioner.InitComplete + 49, // 66: provisioner.Response.plan:type_name -> provisioner.PlanComplete + 51, // 67: provisioner.Response.apply:type_name -> provisioner.ApplyComplete + 53, // 68: provisioner.Response.graph:type_name -> provisioner.GraphComplete + 60, // 69: provisioner.Response.data_upload:type_name -> provisioner.DataUpload + 61, // 70: provisioner.Response.chunk_piece:type_name -> provisioner.ChunkPiece + 60, // 71: provisioner.FileUpload.data_upload:type_name -> provisioner.DataUpload + 61, // 72: provisioner.FileUpload.chunk_piece:type_name -> provisioner.ChunkPiece + 59, // 73: provisioner.FileUpload.error:type_name -> provisioner.FailedFile + 8, // 74: provisioner.DataUpload.upload_type:type_name -> provisioner.DataUploadType + 56, // 75: provisioner.Provisioner.Session:input_type -> provisioner.Request + 57, // 76: provisioner.Provisioner.Session:output_type -> provisioner.Response + 76, // [76:77] is the sub-list for method output_type + 75, // [75:76] is the sub-list for method input_type + 75, // [75:75] is the sub-list for extension type_name + 75, // [75:75] is the sub-list for extension extendee + 0, // [0:75] is the sub-list for field type_name } func init() { file_provisionersdk_proto_provisioner_proto_init() } @@ -6458,18 +6354,6 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UserSecretValue); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_provisionersdk_proto_provisioner_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PlanRequest); i { case 0: return &v.state @@ -6481,7 +6365,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PlanComplete); i { case 0: return &v.state @@ -6493,7 +6377,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ApplyRequest); i { case 0: return &v.state @@ -6505,7 +6389,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ApplyComplete); i { case 0: return &v.state @@ -6517,7 +6401,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GraphRequest); i { case 0: return &v.state @@ -6529,7 +6413,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GraphComplete); i { case 0: return &v.state @@ -6541,7 +6425,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Timing); i { case 0: return &v.state @@ -6553,7 +6437,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CancelRequest); i { case 0: return &v.state @@ -6565,7 +6449,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Request); i { case 0: return &v.state @@ -6577,7 +6461,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Response); i { case 0: return &v.state @@ -6589,7 +6473,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FileUpload); i { case 0: return &v.state @@ -6601,7 +6485,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FailedFile); i { case 0: return &v.state @@ -6613,7 +6497,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DataUpload); i { case 0: return &v.state @@ -6625,7 +6509,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ChunkPiece); i { case 0: return &v.state @@ -6637,7 +6521,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Agent_Metadata); i { case 0: return &v.state @@ -6649,7 +6533,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Resource_Metadata); i { case 0: return &v.state @@ -6669,7 +6553,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } file_provisionersdk_proto_provisioner_proto_msgTypes[32].OneofWrappers = []interface{}{} file_provisionersdk_proto_provisioner_proto_msgTypes[34].OneofWrappers = []interface{}{} - file_provisionersdk_proto_provisioner_proto_msgTypes[48].OneofWrappers = []interface{}{ + file_provisionersdk_proto_provisioner_proto_msgTypes[47].OneofWrappers = []interface{}{ (*Request_Config)(nil), (*Request_Parse)(nil), (*Request_Init)(nil), @@ -6679,7 +6563,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { (*Request_Cancel)(nil), (*Request_File)(nil), } - file_provisionersdk_proto_provisioner_proto_msgTypes[49].OneofWrappers = []interface{}{ + file_provisionersdk_proto_provisioner_proto_msgTypes[48].OneofWrappers = []interface{}{ (*Response_Log)(nil), (*Response_Parse)(nil), (*Response_Init)(nil), @@ -6689,7 +6573,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { (*Response_DataUpload)(nil), (*Response_ChunkPiece)(nil), } - file_provisionersdk_proto_provisioner_proto_msgTypes[50].OneofWrappers = []interface{}{ + file_provisionersdk_proto_provisioner_proto_msgTypes[49].OneofWrappers = []interface{}{ (*FileUpload_DataUpload)(nil), (*FileUpload_ChunkPiece)(nil), (*FileUpload_Error)(nil), @@ -6700,7 +6584,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_provisionersdk_proto_provisioner_proto_rawDesc, NumEnums: 9, - NumMessages: 58, + NumMessages: 57, NumExtensions: 0, NumServices: 1, }, diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index 89f9f9bf92..c57809f615 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -422,29 +422,6 @@ message InitComplete { bytes module_files_hash = 5; } -// UserSecretValue carries a single user secret to a provisioner. env_name and -// file_path describe the bindings the user requested when creating the secret. -// The terraform provisioner exposes secrets via CODER_SECRET_ENV_* and -// CODER_SECRET_FILE_* environment variables consumed by terraform-provider-coder's -// coder_secret data source -message UserSecretValue { - // Environment variable name the user selected (e.g. "GITHUB_TOKEN"). Intended - // to be treated as an opaque lookup key, i.e. consumers must preserve it - // verbatim when matching against a data.coder_secret.env_name attribute. - // Consumers can assume names are POSIX-compliant. Optional: env_name and - // file_path are independent. - string env_name = 1; - // Filesystem path the user requested this secret be bound to (e.g. "~/creds" - // or "/etc/creds"). This path is not expanded. Expansion happens only where - // the secret is actually materialized on disk. Intended to be treated as an - // opaque lookup key, i.e. consumers must preserve it verbatim when matching - // against a data.coder_secret.file attribute. Optional; env_name and - // file_path are independent. - string file_path = 2; - // Secret value, which may be arbitrary binary data. - bytes value = 3; -} - // PlanRequest asks the provisioner to plan what resources & parameters it will create message PlanRequest { Metadata metadata = 1; @@ -456,11 +433,9 @@ message PlanRequest { // state is the provisioner state (if any) bytes state = 6; - // User secrets to make available during plan. Not carried on ApplyRequest - // because plan evaluates data.coder_secret references and bakes the - // resolved values into plan state, so apply does not need the raw secrets. - // Provisioner-specific handling is documented on the UserSecretValue message. - repeated UserSecretValue user_secrets = 7; + // Reserved 7 for `user_secrets` introduced in v1.17 (#24542) and removed + // in v1.18 along with the rest of the `coder_secret` Terraform integration. + reserved 7; } // PlanComplete indicates a request to plan completed. diff --git a/site/e2e/provisionerGenerated.ts b/site/e2e/provisionerGenerated.ts index 838d92c3f5..0a0195befd 100644 --- a/site/e2e/provisionerGenerated.ts +++ b/site/e2e/provisionerGenerated.ts @@ -477,35 +477,6 @@ export interface InitComplete { moduleFilesHash: Uint8Array; } -/** - * UserSecretValue carries a single user secret to a provisioner. env_name and - * file_path describe the bindings the user requested when creating the secret. - * The terraform provisioner exposes secrets via CODER_SECRET_ENV_* and - * CODER_SECRET_FILE_* environment variables consumed by terraform-provider-coder's - * coder_secret data source - */ -export interface UserSecretValue { - /** - * Environment variable name the user selected (e.g. "GITHUB_TOKEN"). Intended - * to be treated as an opaque lookup key, i.e. consumers must preserve it - * verbatim when matching against a data.coder_secret.env_name attribute. - * Consumers can assume names are POSIX-compliant. Optional: env_name and - * file_path are independent. - */ - envName: string; - /** - * Filesystem path the user requested this secret be bound to (e.g. "~/creds" - * or "/etc/creds"). This path is not expanded. Expansion happens only where - * the secret is actually materialized on disk. Intended to be treated as an - * opaque lookup key, i.e. consumers must preserve it verbatim when matching - * against a data.coder_secret.file attribute. Optional; env_name and - * file_path are independent. - */ - filePath: string; - /** Secret value, which may be arbitrary binary data. */ - value: Uint8Array; -} - /** PlanRequest asks the provisioner to plan what resources & parameters it will create */ export interface PlanRequest { metadata: Metadata | undefined; @@ -515,13 +486,6 @@ export interface PlanRequest { previousParameterValues: RichParameterValue[]; /** state is the provisioner state (if any) */ state: Uint8Array; - /** - * User secrets to make available during plan. Not carried on ApplyRequest - * because plan evaluates data.coder_secret references and bakes the - * resolved values into plan state, so apply does not need the raw secrets. - * Provisioner-specific handling is documented on the UserSecretValue message. - */ - userSecrets: UserSecretValue[]; } /** PlanComplete indicates a request to plan completed. */ @@ -1512,21 +1476,6 @@ export const InitComplete = { }, }; -export const UserSecretValue = { - encode(message: UserSecretValue, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.envName !== "") { - writer.uint32(10).string(message.envName); - } - if (message.filePath !== "") { - writer.uint32(18).string(message.filePath); - } - if (message.value.length !== 0) { - writer.uint32(26).bytes(message.value); - } - return writer; - }, -}; - export const PlanRequest = { encode(message: PlanRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { if (message.metadata !== undefined) { @@ -1547,9 +1496,6 @@ export const PlanRequest = { if (message.state.length !== 0) { writer.uint32(50).bytes(message.state); } - for (const v of message.userSecrets) { - UserSecretValue.encode(v!, writer.uint32(58).fork()).ldelim(); - } return writer; }, }; diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index b3cdcc63bd..c66edeedf7 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -4171,9 +4171,8 @@ export const DisplayApps: DisplayApp[] = [ // From codersdk/parameters.go export interface DynamicParametersRequest { /** - * ID identifies the request for response ordering. Websocket response - * IDs are monotonically increasing and may exceed the request ID when - * server-side events trigger additional renders. + * ID identifies the request. The response contains the same + * ID so that the client can match it to the request. */ readonly id: number; readonly inputs: Record; @@ -4188,7 +4187,6 @@ export interface DynamicParametersResponse { readonly id: number; readonly diagnostics: readonly FriendlyDiagnostic[]; readonly parameters: readonly PreviewParameter[]; - readonly secret_requirements?: readonly SecretRequirementStatus[]; } // From codersdk/chats.go @@ -6944,12 +6942,6 @@ export interface RequestOneTimePasscodeRequest { // From codersdk/workspaces.go export interface ResolveAutostartResponse { readonly parameter_mismatch: boolean; - /** - * SecretMismatch is true when the active template version declares - * `coder_secret` requirements that the workspace owner's secrets do not - * satisfy. - */ - readonly secret_mismatch: boolean; } // From codersdk/audit.go @@ -7241,14 +7233,6 @@ export interface STUNReport { readonly Error: string | null; } -// From codersdk/parameters.go -export interface SecretRequirementStatus { - readonly env?: string; - readonly file?: string; - readonly help_message: string; - readonly satisfied: boolean; -} - // From serpent/serpent.go /** * Annotations is an arbitrary key-mapping used to extend the Option and Command types.