diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go
index e562bbd1f7160..4c252e6d32c5b 100644
--- a/coderd/database/dbauthz/dbauthz_test.go
+++ b/coderd/database/dbauthz/dbauthz_test.go
@@ -3997,6 +3997,7 @@ func (s *MethodTestSuite) TestSystemFunctions() {
Health: database.WorkspaceAppHealthDisabled,
SharingLevel: database.AppSharingLevelOwner,
OpenIn: database.WorkspaceAppOpenInSlimWindow,
+ CORSBehavior: database.AppCorsBehaviorSimple,
}).Asserts(rbac.ResourceSystem, policy.ActionCreate)
}))
s.Run("InsertWorkspaceResourceMetadata", s.Subtest(func(db database.Store, check *expects) {
diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go
index 854c7c2974fe6..42cb8b3f7bef0 100644
--- a/coderd/database/dbgen/dbgen.go
+++ b/coderd/database/dbgen/dbgen.go
@@ -723,6 +723,7 @@ func WorkspaceApp(t testing.TB, db database.Store, orig database.WorkspaceApp) d
DisplayOrder: takeFirst(orig.DisplayOrder, 1),
Hidden: orig.Hidden,
OpenIn: takeFirst(orig.OpenIn, database.WorkspaceAppOpenInSlimWindow),
+ CORSBehavior: takeFirst(orig.CORSBehavior, database.AppCorsBehaviorSimple),
})
require.NoError(t, err, "insert app")
return resource
diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go
index 1359d2e63484d..899f92e2ee176 100644
--- a/coderd/database/dbmem/dbmem.go
+++ b/coderd/database/dbmem/dbmem.go
@@ -9701,6 +9701,10 @@ func (q *FakeQuerier) InsertWorkspaceApp(_ context.Context, arg database.InsertW
arg.OpenIn = database.WorkspaceAppOpenInSlimWindow
}
+ if arg.CORSBehavior == "" {
+ arg.CORSBehavior = database.AppCorsBehaviorSimple
+ }
+
// nolint:gosimple
workspaceApp := database.WorkspaceApp{
ID: arg.ID,
@@ -9721,6 +9725,7 @@ func (q *FakeQuerier) InsertWorkspaceApp(_ context.Context, arg database.InsertW
Hidden: arg.Hidden,
DisplayOrder: arg.DisplayOrder,
OpenIn: arg.OpenIn,
+ CORSBehavior: arg.CORSBehavior,
}
q.workspaceApps = append(q.workspaceApps, workspaceApp)
return workspaceApp, nil
diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql
index 83d998b2b9a3e..5b56820f46de9 100644
--- a/coderd/database/dump.sql
+++ b/coderd/database/dump.sql
@@ -10,6 +10,11 @@ CREATE TYPE api_key_scope AS ENUM (
'application_connect'
);
+CREATE TYPE app_cors_behavior AS ENUM (
+ 'simple',
+ 'passthru'
+);
+
CREATE TYPE app_sharing_level AS ENUM (
'owner',
'authenticated',
@@ -1933,7 +1938,8 @@ CREATE TABLE workspace_apps (
external boolean DEFAULT false NOT NULL,
display_order integer DEFAULT 0 NOT NULL,
hidden boolean DEFAULT false NOT NULL,
- open_in workspace_app_open_in DEFAULT 'slim-window'::workspace_app_open_in NOT NULL
+ open_in workspace_app_open_in DEFAULT 'slim-window'::workspace_app_open_in NOT NULL,
+ cors_behavior app_cors_behavior DEFAULT 'simple'::app_cors_behavior NOT NULL
);
COMMENT ON COLUMN workspace_apps.display_order IS 'Specifies the order in which to display agent app in user interfaces.';
diff --git a/coderd/database/migrations/000318_workspace_app_cors_behavior.down.sql b/coderd/database/migrations/000318_workspace_app_cors_behavior.down.sql
new file mode 100644
index 0000000000000..5f6e26306594e
--- /dev/null
+++ b/coderd/database/migrations/000318_workspace_app_cors_behavior.down.sql
@@ -0,0 +1,4 @@
+ALTER TABLE workspace_apps
+ DROP COLUMN IF EXISTS cors_behavior;
+
+DROP TYPE IF EXISTS app_cors_behavior;
\ No newline at end of file
diff --git a/coderd/database/migrations/000318_workspace_app_cors_behavior.up.sql b/coderd/database/migrations/000318_workspace_app_cors_behavior.up.sql
new file mode 100644
index 0000000000000..aab91bf4024e7
--- /dev/null
+++ b/coderd/database/migrations/000318_workspace_app_cors_behavior.up.sql
@@ -0,0 +1,10 @@
+CREATE TYPE app_cors_behavior AS ENUM (
+ 'simple',
+ 'passthru'
+);
+
+-- https://www.postgresql.org/docs/16/sql-altertable.html
+-- When a column is added with ADD COLUMN and a non-volatile DEFAULT is specified, the default is evaluated at the time
+-- of the statement and the result stored in the table's metadata. That value will be used for the column for all existing rows.
+ALTER TABLE workspace_apps
+ ADD COLUMN cors_behavior app_cors_behavior NOT NULL DEFAULT 'simple'::app_cors_behavior;
\ No newline at end of file
diff --git a/coderd/database/models.go b/coderd/database/models.go
index f817ff2712d54..a5c2dccd7a7c4 100644
--- a/coderd/database/models.go
+++ b/coderd/database/models.go
@@ -74,6 +74,64 @@ func AllAPIKeyScopeValues() []APIKeyScope {
}
}
+type AppCORSBehavior string
+
+const (
+ AppCorsBehaviorSimple AppCORSBehavior = "simple"
+ AppCorsBehaviorPassthru AppCORSBehavior = "passthru"
+)
+
+func (e *AppCORSBehavior) Scan(src interface{}) error {
+ switch s := src.(type) {
+ case []byte:
+ *e = AppCORSBehavior(s)
+ case string:
+ *e = AppCORSBehavior(s)
+ default:
+ return fmt.Errorf("unsupported scan type for AppCORSBehavior: %T", src)
+ }
+ return nil
+}
+
+type NullAppCORSBehavior struct {
+ AppCORSBehavior AppCORSBehavior `json:"app_cors_behavior"`
+ Valid bool `json:"valid"` // Valid is true if AppCORSBehavior is not NULL
+}
+
+// Scan implements the Scanner interface.
+func (ns *NullAppCORSBehavior) Scan(value interface{}) error {
+ if value == nil {
+ ns.AppCORSBehavior, ns.Valid = "", false
+ return nil
+ }
+ ns.Valid = true
+ return ns.AppCORSBehavior.Scan(value)
+}
+
+// Value implements the driver Valuer interface.
+func (ns NullAppCORSBehavior) Value() (driver.Value, error) {
+ if !ns.Valid {
+ return nil, nil
+ }
+ return string(ns.AppCORSBehavior), nil
+}
+
+func (e AppCORSBehavior) Valid() bool {
+ switch e {
+ case AppCorsBehaviorSimple,
+ AppCorsBehaviorPassthru:
+ return true
+ }
+ return false
+}
+
+func AllAppCORSBehaviorValues() []AppCORSBehavior {
+ return []AppCORSBehavior{
+ AppCorsBehaviorSimple,
+ AppCorsBehaviorPassthru,
+ }
+}
+
type AppSharingLevel string
const (
@@ -3527,8 +3585,9 @@ type WorkspaceApp struct {
// Specifies the order in which to display agent app in user interfaces.
DisplayOrder int32 `db:"display_order" json:"display_order"`
// Determines if the app is not shown in user interfaces.
- Hidden bool `db:"hidden" json:"hidden"`
- OpenIn WorkspaceAppOpenIn `db:"open_in" json:"open_in"`
+ Hidden bool `db:"hidden" json:"hidden"`
+ OpenIn WorkspaceAppOpenIn `db:"open_in" json:"open_in"`
+ CORSBehavior AppCORSBehavior `db:"cors_behavior" json:"cors_behavior"`
}
// Audit sessions for workspace apps, the data in this table is ephemeral and is used to deduplicate audit log entries for workspace apps. While a session is active, the same data will not be logged again. This table does not store historical data.
diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go
index 60416b1a35730..afc9987c6ac46 100644
--- a/coderd/database/queries.sql.go
+++ b/coderd/database/queries.sql.go
@@ -15646,7 +15646,7 @@ func (q *sqlQuerier) GetLatestWorkspaceAppStatusesByWorkspaceIDs(ctx context.Con
}
const getWorkspaceAppByAgentIDAndSlug = `-- name: GetWorkspaceAppByAgentIDAndSlug :one
-SELECT id, created_at, agent_id, display_name, icon, command, url, healthcheck_url, healthcheck_interval, healthcheck_threshold, health, subdomain, sharing_level, slug, external, display_order, hidden, open_in FROM workspace_apps WHERE agent_id = $1 AND slug = $2
+SELECT id, created_at, agent_id, display_name, icon, command, url, healthcheck_url, healthcheck_interval, healthcheck_threshold, health, subdomain, sharing_level, slug, external, display_order, hidden, open_in, cors_behavior FROM workspace_apps WHERE agent_id = $1 AND slug = $2
`
type GetWorkspaceAppByAgentIDAndSlugParams struct {
@@ -15676,6 +15676,7 @@ func (q *sqlQuerier) GetWorkspaceAppByAgentIDAndSlug(ctx context.Context, arg Ge
&i.DisplayOrder,
&i.Hidden,
&i.OpenIn,
+ &i.CORSBehavior,
)
return i, err
}
@@ -15717,7 +15718,7 @@ func (q *sqlQuerier) GetWorkspaceAppStatusesByAppIDs(ctx context.Context, ids []
}
const getWorkspaceAppsByAgentID = `-- name: GetWorkspaceAppsByAgentID :many
-SELECT id, created_at, agent_id, display_name, icon, command, url, healthcheck_url, healthcheck_interval, healthcheck_threshold, health, subdomain, sharing_level, slug, external, display_order, hidden, open_in FROM workspace_apps WHERE agent_id = $1 ORDER BY slug ASC
+SELECT id, created_at, agent_id, display_name, icon, command, url, healthcheck_url, healthcheck_interval, healthcheck_threshold, health, subdomain, sharing_level, slug, external, display_order, hidden, open_in, cors_behavior FROM workspace_apps WHERE agent_id = $1 ORDER BY slug ASC
`
func (q *sqlQuerier) GetWorkspaceAppsByAgentID(ctx context.Context, agentID uuid.UUID) ([]WorkspaceApp, error) {
@@ -15748,6 +15749,7 @@ func (q *sqlQuerier) GetWorkspaceAppsByAgentID(ctx context.Context, agentID uuid
&i.DisplayOrder,
&i.Hidden,
&i.OpenIn,
+ &i.CORSBehavior,
); err != nil {
return nil, err
}
@@ -15763,7 +15765,7 @@ func (q *sqlQuerier) GetWorkspaceAppsByAgentID(ctx context.Context, agentID uuid
}
const getWorkspaceAppsByAgentIDs = `-- name: GetWorkspaceAppsByAgentIDs :many
-SELECT id, created_at, agent_id, display_name, icon, command, url, healthcheck_url, healthcheck_interval, healthcheck_threshold, health, subdomain, sharing_level, slug, external, display_order, hidden, open_in FROM workspace_apps WHERE agent_id = ANY($1 :: uuid [ ]) ORDER BY slug ASC
+SELECT id, created_at, agent_id, display_name, icon, command, url, healthcheck_url, healthcheck_interval, healthcheck_threshold, health, subdomain, sharing_level, slug, external, display_order, hidden, open_in, cors_behavior FROM workspace_apps WHERE agent_id = ANY($1 :: uuid [ ]) ORDER BY slug ASC
`
func (q *sqlQuerier) GetWorkspaceAppsByAgentIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceApp, error) {
@@ -15794,6 +15796,7 @@ func (q *sqlQuerier) GetWorkspaceAppsByAgentIDs(ctx context.Context, ids []uuid.
&i.DisplayOrder,
&i.Hidden,
&i.OpenIn,
+ &i.CORSBehavior,
); err != nil {
return nil, err
}
@@ -15809,7 +15812,7 @@ func (q *sqlQuerier) GetWorkspaceAppsByAgentIDs(ctx context.Context, ids []uuid.
}
const getWorkspaceAppsCreatedAfter = `-- name: GetWorkspaceAppsCreatedAfter :many
-SELECT id, created_at, agent_id, display_name, icon, command, url, healthcheck_url, healthcheck_interval, healthcheck_threshold, health, subdomain, sharing_level, slug, external, display_order, hidden, open_in FROM workspace_apps WHERE created_at > $1 ORDER BY slug ASC
+SELECT id, created_at, agent_id, display_name, icon, command, url, healthcheck_url, healthcheck_interval, healthcheck_threshold, health, subdomain, sharing_level, slug, external, display_order, hidden, open_in, cors_behavior FROM workspace_apps WHERE created_at > $1 ORDER BY slug ASC
`
func (q *sqlQuerier) GetWorkspaceAppsCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceApp, error) {
@@ -15840,6 +15843,7 @@ func (q *sqlQuerier) GetWorkspaceAppsCreatedAfter(ctx context.Context, createdAt
&i.DisplayOrder,
&i.Hidden,
&i.OpenIn,
+ &i.CORSBehavior,
); err != nil {
return nil, err
}
@@ -15868,6 +15872,7 @@ INSERT INTO
external,
subdomain,
sharing_level,
+ cors_behavior,
healthcheck_url,
healthcheck_interval,
healthcheck_threshold,
@@ -15877,7 +15882,7 @@ INSERT INTO
open_in
)
VALUES
- ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) RETURNING id, created_at, agent_id, display_name, icon, command, url, healthcheck_url, healthcheck_interval, healthcheck_threshold, health, subdomain, sharing_level, slug, external, display_order, hidden, open_in
+ ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19) RETURNING id, created_at, agent_id, display_name, icon, command, url, healthcheck_url, healthcheck_interval, healthcheck_threshold, health, subdomain, sharing_level, slug, external, display_order, hidden, open_in, cors_behavior
`
type InsertWorkspaceAppParams struct {
@@ -15892,6 +15897,7 @@ type InsertWorkspaceAppParams struct {
External bool `db:"external" json:"external"`
Subdomain bool `db:"subdomain" json:"subdomain"`
SharingLevel AppSharingLevel `db:"sharing_level" json:"sharing_level"`
+ CORSBehavior AppCORSBehavior `db:"cors_behavior" json:"cors_behavior"`
HealthcheckUrl string `db:"healthcheck_url" json:"healthcheck_url"`
HealthcheckInterval int32 `db:"healthcheck_interval" json:"healthcheck_interval"`
HealthcheckThreshold int32 `db:"healthcheck_threshold" json:"healthcheck_threshold"`
@@ -15914,6 +15920,7 @@ func (q *sqlQuerier) InsertWorkspaceApp(ctx context.Context, arg InsertWorkspace
arg.External,
arg.Subdomain,
arg.SharingLevel,
+ arg.CORSBehavior,
arg.HealthcheckUrl,
arg.HealthcheckInterval,
arg.HealthcheckThreshold,
@@ -15942,6 +15949,7 @@ func (q *sqlQuerier) InsertWorkspaceApp(ctx context.Context, arg InsertWorkspace
&i.DisplayOrder,
&i.Hidden,
&i.OpenIn,
+ &i.CORSBehavior,
)
return i, err
}
diff --git a/coderd/database/queries/workspaceapps.sql b/coderd/database/queries/workspaceapps.sql
index cd1cddb454b88..b41fa88e5879a 100644
--- a/coderd/database/queries/workspaceapps.sql
+++ b/coderd/database/queries/workspaceapps.sql
@@ -24,6 +24,7 @@ INSERT INTO
external,
subdomain,
sharing_level,
+ cors_behavior,
healthcheck_url,
healthcheck_interval,
healthcheck_threshold,
@@ -33,7 +34,7 @@ INSERT INTO
open_in
)
VALUES
- ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) RETURNING *;
+ ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19) RETURNING *;
-- name: UpdateWorkspaceAppHealthByID :exec
UPDATE
diff --git a/coderd/database/sqlc.yaml b/coderd/database/sqlc.yaml
index b43281a3f1051..96a0142222bf0 100644
--- a/coderd/database/sqlc.yaml
+++ b/coderd/database/sqlc.yaml
@@ -147,6 +147,8 @@ sql:
crypto_key_feature_workspace_apps_api_key: CryptoKeyFeatureWorkspaceAppsAPIKey
crypto_key_feature_oidc_convert: CryptoKeyFeatureOIDCConvert
stale_interval_ms: StaleIntervalMS
+ app_cors_behavior: AppCORSBehavior
+ cors_behavior: CORSBehavior
rules:
- name: do-not-use-public-schema-in-queries
message: "do not use public schema in queries"
diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go
index 9362d2f3e5a85..28f3e13acb7be 100644
--- a/coderd/provisionerdserver/provisionerdserver.go
+++ b/coderd/provisionerdserver/provisionerdserver.go
@@ -2225,6 +2225,14 @@ func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
openIn = database.WorkspaceAppOpenInSlimWindow
}
+ var corsBehavior database.AppCORSBehavior
+ switch app.CorsBehavior {
+ case sdkproto.AppCORSBehavior_PASSTHRU:
+ corsBehavior = database.AppCorsBehaviorPassthru
+ default:
+ corsBehavior = database.AppCorsBehaviorSimple
+ }
+
dbApp, err := db.InsertWorkspaceApp(ctx, database.InsertWorkspaceAppParams{
ID: uuid.New(),
CreatedAt: dbtime.Now(),
@@ -2251,6 +2259,7 @@ func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.
DisplayOrder: int32(app.Order),
Hidden: app.Hidden,
OpenIn: openIn,
+ CORSBehavior: corsBehavior,
})
if err != nil {
return xerrors.Errorf("insert app: %w", err)
diff --git a/coderd/workspaceapps/apptest/apptest.go b/coderd/workspaceapps/apptest/apptest.go
index 4e48e60d2d47f..4e77d6cb1d7d3 100644
--- a/coderd/workspaceapps/apptest/apptest.go
+++ b/coderd/workspaceapps/apptest/apptest.go
@@ -473,6 +473,400 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
})
})
+ t.Run("WorkspaceApplicationCORS", func(t *testing.T) {
+ t.Parallel()
+
+ const external = "https://example.com"
+
+ unauthenticatedClient := func(t *testing.T, appDetails *Details) *codersdk.Client {
+ c := appDetails.AppClient(t)
+ c.SetSessionToken("")
+ return c
+ }
+
+ authenticatedClient := func(t *testing.T, appDetails *Details) *codersdk.Client {
+ uc, _ := coderdtest.CreateAnotherUser(t, appDetails.SDKClient, appDetails.FirstUser.OrganizationID, rbac.RoleMember())
+ c := appDetails.AppClient(t)
+ c.SetSessionToken(uc.SessionToken())
+ return c
+ }
+
+ ownSubdomain := func(details *Details, app App) string {
+ url := details.SubdomainAppURL(app)
+ return url.Scheme + "://" + url.Host
+ }
+
+ externalOrigin := func(*Details, App) string {
+ return external
+ }
+
+ tests := []struct {
+ name string
+ app func(details *Details) App
+ client func(t *testing.T, appDetails *Details) *codersdk.Client
+ behavior codersdk.AppCORSBehavior
+ httpMethod string
+ origin func(details *Details, app App) string
+ expectedStatusCode int
+ checkRequestHeaders func(t *testing.T, origin string, req http.Header)
+ checkResponseHeaders func(t *testing.T, origin string, resp http.Header)
+ }{
+ // Public
+ {
+ // The default behavior is to accept preflight requests from the request origin if it matches the app's own subdomain.
+ name: "Default/Public/Preflight/Subdomain",
+ app: func(details *Details) App { return details.Apps.PublicCORSDefault },
+ behavior: codersdk.AppCORSBehaviorSimple,
+ client: unauthenticatedClient,
+ httpMethod: http.MethodOptions,
+ origin: ownSubdomain,
+ expectedStatusCode: http.StatusOK,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.Equal(t, origin, resp.Get("Access-Control-Allow-Origin"))
+ assert.Contains(t, resp.Get("Access-Control-Allow-Methods"), http.MethodGet)
+ assert.Equal(t, "true", resp.Get("Access-Control-Allow-Credentials"))
+ },
+ },
+ {
+ // The default behavior is to reject preflight requests from origins other than the app's own subdomain.
+ name: "Default/Public/Preflight/External",
+ app: func(details *Details) App { return details.Apps.PublicCORSDefault },
+ behavior: codersdk.AppCORSBehaviorSimple,
+ client: unauthenticatedClient,
+ httpMethod: http.MethodOptions,
+ origin: externalOrigin,
+ expectedStatusCode: http.StatusOK,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ // We don't add a valid Allow-Origin header for requests we won't proxy.
+ assert.Empty(t, resp.Get("Access-Control-Allow-Origin"))
+ },
+ },
+ {
+ // A request without an Origin header would be rejected by an actual browser since it lacks CORS headers.
+ name: "Default/Public/GET/NoOrigin",
+ app: func(details *Details) App { return details.Apps.PublicCORSDefault },
+ behavior: codersdk.AppCORSBehaviorSimple,
+ client: unauthenticatedClient,
+ origin: func(*Details, App) string { return "" },
+ httpMethod: http.MethodGet,
+ expectedStatusCode: http.StatusOK,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.Empty(t, resp.Get("Access-Control-Allow-Origin"))
+ assert.Empty(t, resp.Get("Access-Control-Allow-Headers"))
+ assert.Empty(t, resp.Get("Access-Control-Allow-Credentials"))
+ // Added by the app handler.
+ assert.Equal(t, "simple", resp.Get("X-CORS-Handler"))
+ },
+ },
+ {
+ // The passthru behavior will pass through the request headers to the upstream app.
+ name: "Passthru/Public/Preflight/Subdomain",
+ app: func(details *Details) App { return details.Apps.PublicCORSPassthru },
+ behavior: codersdk.AppCORSBehaviorPassthru,
+ client: unauthenticatedClient,
+ origin: ownSubdomain,
+ httpMethod: http.MethodOptions,
+ expectedStatusCode: http.StatusOK,
+ checkRequestHeaders: func(t *testing.T, origin string, req http.Header) {
+ assert.Equal(t, origin, req.Get("Origin"))
+ assert.Equal(t, "GET", req.Get("Access-Control-Request-Method"))
+ },
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.Equal(t, origin, resp.Get("Access-Control-Allow-Origin"))
+ assert.Equal(t, http.MethodGet, resp.Get("Access-Control-Allow-Methods"))
+ // Added by the app handler.
+ assert.Equal(t, "passthru", resp.Get("X-CORS-Handler"))
+ },
+ },
+ {
+ // Identical to the previous test, but the origin is different.
+ name: "Passthru/Public/PreflightOther",
+ app: func(details *Details) App { return details.Apps.PublicCORSPassthru },
+ behavior: codersdk.AppCORSBehaviorPassthru,
+ client: unauthenticatedClient,
+ origin: externalOrigin,
+ httpMethod: http.MethodOptions,
+ expectedStatusCode: http.StatusOK,
+ checkRequestHeaders: func(t *testing.T, origin string, req http.Header) {
+ assert.Equal(t, origin, req.Get("Origin"))
+ assert.Equal(t, "GET", req.Get("Access-Control-Request-Method"))
+ assert.Equal(t, "X-Got-Host", req.Get("Access-Control-Request-Headers"))
+ },
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.Equal(t, origin, resp.Get("Access-Control-Allow-Origin"))
+ assert.Equal(t, http.MethodGet, resp.Get("Access-Control-Allow-Methods"))
+ // Added by the app handler.
+ assert.Equal(t, "passthru", resp.Get("X-CORS-Handler"))
+ },
+ },
+ {
+ // A request without an Origin header would be rejected by an actual browser since it lacks CORS headers.
+ name: "Passthru/Public/GET/NoOrigin",
+ app: func(details *Details) App { return details.Apps.PublicCORSPassthru },
+ behavior: codersdk.AppCORSBehaviorPassthru,
+ client: unauthenticatedClient,
+ origin: func(*Details, App) string { return "" },
+ httpMethod: http.MethodGet,
+ expectedStatusCode: http.StatusOK,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.Empty(t, resp.Get("Access-Control-Allow-Origin"))
+ assert.Empty(t, resp.Get("Access-Control-Allow-Headers"))
+ assert.Empty(t, resp.Get("Access-Control-Allow-Credentials"))
+ // Added by the app handler.
+ assert.Equal(t, "passthru", resp.Get("X-CORS-Handler"))
+ },
+ },
+ // Authenticated
+ {
+ // Same behavior as Default/Public/Preflight/Subdomain.
+ name: "Default/Authenticated/Preflight/Subdomain",
+ app: func(details *Details) App { return details.Apps.AuthenticatedCORSDefault },
+ behavior: codersdk.AppCORSBehaviorSimple,
+ client: authenticatedClient,
+ origin: ownSubdomain,
+ httpMethod: http.MethodOptions,
+ expectedStatusCode: http.StatusOK,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.Equal(t, origin, resp.Get("Access-Control-Allow-Origin"))
+ assert.Contains(t, resp.Get("Access-Control-Allow-Methods"), http.MethodGet)
+ assert.Equal(t, "true", resp.Get("Access-Control-Allow-Credentials"))
+ assert.Equal(t, "X-Got-Host", resp.Get("Access-Control-Allow-Headers"))
+ },
+ },
+ {
+ // Same behavior as Default/Public/Preflight/External.
+ name: "Default/Authenticated/Preflight/External",
+ app: func(details *Details) App { return details.Apps.AuthenticatedCORSDefault },
+ behavior: codersdk.AppCORSBehaviorSimple,
+ client: authenticatedClient,
+ origin: externalOrigin,
+ httpMethod: http.MethodOptions,
+ expectedStatusCode: http.StatusOK,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.Empty(t, resp.Get("Access-Control-Allow-Origin"))
+ },
+ },
+ {
+ // An authenticated request to the app is allowed from its own subdomain.
+ name: "Default/Authenticated/GET/Subdomain",
+ app: func(details *Details) App { return details.Apps.AuthenticatedCORSDefault },
+ behavior: codersdk.AppCORSBehaviorSimple,
+ client: authenticatedClient,
+ origin: ownSubdomain,
+ httpMethod: http.MethodGet,
+ expectedStatusCode: http.StatusOK,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.Equal(t, origin, resp.Get("Access-Control-Allow-Origin"))
+ assert.Equal(t, "true", resp.Get("Access-Control-Allow-Credentials"))
+ // Added by the app handler.
+ assert.Equal(t, "simple", resp.Get("X-CORS-Handler"))
+ },
+ },
+ {
+ // An authenticated request to the app is allowed from an external origin.
+ // The origin doesn't match the app's own subdomain, so the CORS headers are not added.
+ name: "Default/Authenticated/GET/External",
+ app: func(details *Details) App { return details.Apps.AuthenticatedCORSDefault },
+ behavior: codersdk.AppCORSBehaviorSimple,
+ client: authenticatedClient,
+ origin: externalOrigin,
+ httpMethod: http.MethodGet,
+ expectedStatusCode: http.StatusOK,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.Empty(t, resp.Get("Access-Control-Allow-Origin"))
+ assert.Empty(t, resp.Get("Access-Control-Allow-Headers"))
+ assert.Empty(t, resp.Get("Access-Control-Allow-Credentials"))
+ // Added by the app handler.
+ assert.Equal(t, "simple", resp.Get("X-CORS-Handler"))
+ },
+ },
+ {
+ // The request is rejected because the client is unauthenticated.
+ name: "Passthru/Unauthenticated/Preflight/Subdomain",
+ app: func(details *Details) App { return details.Apps.AuthenticatedCORSPassthru },
+ behavior: codersdk.AppCORSBehaviorPassthru,
+ client: unauthenticatedClient,
+ origin: ownSubdomain,
+ httpMethod: http.MethodOptions,
+ expectedStatusCode: http.StatusSeeOther,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.NotEmpty(t, resp.Get("Location"))
+ },
+ },
+ {
+ // Same behavior as the above test, but the origin is different.
+ name: "Passthru/Unauthenticated/Preflight/External",
+ app: func(details *Details) App { return details.Apps.AuthenticatedCORSPassthru },
+ behavior: codersdk.AppCORSBehaviorPassthru,
+ client: unauthenticatedClient,
+ origin: externalOrigin,
+ httpMethod: http.MethodOptions,
+ expectedStatusCode: http.StatusSeeOther,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.NotEmpty(t, resp.Get("Location"))
+ },
+ },
+ {
+ // The request is rejected because the client is unauthenticated.
+ name: "Passthru/Unauthenticated/GET/Subdomain",
+ app: func(details *Details) App { return details.Apps.AuthenticatedCORSPassthru },
+ behavior: codersdk.AppCORSBehaviorPassthru,
+ client: unauthenticatedClient,
+ origin: ownSubdomain,
+ httpMethod: http.MethodGet,
+ expectedStatusCode: http.StatusSeeOther,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.NotEmpty(t, resp.Get("Location"))
+ },
+ },
+ {
+ // Same behavior as the above test, but the origin is different.
+ name: "Passthru/Unauthenticated/GET/External",
+ app: func(details *Details) App { return details.Apps.AuthenticatedCORSPassthru },
+ behavior: codersdk.AppCORSBehaviorPassthru,
+ client: unauthenticatedClient,
+ origin: externalOrigin,
+ httpMethod: http.MethodGet,
+ expectedStatusCode: http.StatusSeeOther,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.NotEmpty(t, resp.Get("Location"))
+ },
+ },
+ {
+ // The request is allowed because the client is authenticated.
+ name: "Passthru/Authenticated/Preflight/Subdomain",
+ app: func(details *Details) App { return details.Apps.AuthenticatedCORSPassthru },
+ behavior: codersdk.AppCORSBehaviorPassthru,
+ client: authenticatedClient,
+ origin: ownSubdomain,
+ httpMethod: http.MethodOptions,
+ expectedStatusCode: http.StatusOK,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.Equal(t, origin, resp.Get("Access-Control-Allow-Origin"))
+ assert.Equal(t, http.MethodGet, resp.Get("Access-Control-Allow-Methods"))
+ // Added by the app handler.
+ assert.Equal(t, "passthru", resp.Get("X-CORS-Handler"))
+ },
+ },
+ {
+ // Same behavior as the above test, but the origin is different.
+ name: "Passthru/Authenticated/Preflight/External",
+ app: func(details *Details) App { return details.Apps.AuthenticatedCORSPassthru },
+ behavior: codersdk.AppCORSBehaviorPassthru,
+ client: authenticatedClient,
+ origin: externalOrigin,
+ httpMethod: http.MethodOptions,
+ expectedStatusCode: http.StatusOK,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.Equal(t, origin, resp.Get("Access-Control-Allow-Origin"))
+ assert.Equal(t, http.MethodGet, resp.Get("Access-Control-Allow-Methods"))
+ // Added by the app handler.
+ assert.Equal(t, "passthru", resp.Get("X-CORS-Handler"))
+ },
+ },
+ {
+ // The request is allowed because the client is authenticated.
+ name: "Passthru/Authenticated/GET/Subdomain",
+ app: func(details *Details) App { return details.Apps.AuthenticatedCORSPassthru },
+ behavior: codersdk.AppCORSBehaviorPassthru,
+ client: authenticatedClient,
+ origin: ownSubdomain,
+ httpMethod: http.MethodGet,
+ expectedStatusCode: http.StatusOK,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.Equal(t, origin, resp.Get("Access-Control-Allow-Origin"))
+ assert.Equal(t, http.MethodGet, resp.Get("Access-Control-Allow-Methods"))
+ // Added by the app handler.
+ assert.Equal(t, "passthru", resp.Get("X-CORS-Handler"))
+ },
+ },
+ {
+ // Same behavior as the above test, but the origin is different.
+ name: "Passthru/Authenticated/GET/External",
+ app: func(details *Details) App { return details.Apps.AuthenticatedCORSPassthru },
+ behavior: codersdk.AppCORSBehaviorPassthru,
+ client: authenticatedClient,
+ origin: externalOrigin,
+ httpMethod: http.MethodGet,
+ expectedStatusCode: http.StatusOK,
+ checkResponseHeaders: func(t *testing.T, origin string, resp http.Header) {
+ assert.Equal(t, origin, resp.Get("Access-Control-Allow-Origin"))
+ assert.Equal(t, http.MethodGet, resp.Get("Access-Control-Allow-Methods"))
+ // Added by the app handler.
+ assert.Equal(t, "passthru", resp.Get("X-CORS-Handler"))
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ ctx := testutil.Context(t, testutil.WaitLong)
+
+ var reqHeaders http.Header
+ // Setup an HTTP handler which is the "app"; this handler conditionally responds
+ // to requests based on the CORS behavior
+ appDetails := setupProxyTest(t, &DeploymentOptions{
+ handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ _, err := r.Cookie(codersdk.SessionTokenCookie)
+ assert.ErrorIs(t, err, http.ErrNoCookie)
+
+ // Store the request headers for later assertions
+ reqHeaders = r.Header
+
+ switch tc.behavior {
+ case codersdk.AppCORSBehaviorPassthru:
+ w.Header().Set("X-CORS-Handler", "passthru")
+
+ // Only allow GET and OPTIONS requests
+ if r.Method != http.MethodGet && r.Method != http.MethodOptions {
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ return
+ }
+
+ // If the Origin header is present, add the CORS headers.
+ if origin := r.Header.Get("Origin"); origin != "" {
+ w.Header().Set("Access-Control-Allow-Credentials", "true")
+ w.Header().Set("Access-Control-Allow-Origin", origin)
+ w.Header().Set("Access-Control-Allow-Methods", http.MethodGet)
+ }
+
+ w.WriteHeader(http.StatusOK)
+ case codersdk.AppCORSBehaviorSimple:
+ w.Header().Set("X-CORS-Handler", "simple")
+ }
+ }),
+ })
+
+ // Given: a client and a workspace app
+ client := tc.client(t, appDetails)
+ path := appDetails.SubdomainAppURL(tc.app(appDetails)).String()
+ origin := tc.origin(appDetails, tc.app(appDetails))
+
+ // When: a preflight request is made to an app with a specified CORS behavior
+ resp, err := requestWithRetries(ctx, t, client, tc.httpMethod, path, nil, func(r *http.Request) {
+ // Mimic non-browser clients that don't send the Origin header.
+ if origin != "" {
+ r.Header.Set("Origin", origin)
+ }
+ r.Header.Set("Access-Control-Request-Method", "GET")
+ r.Header.Set("Access-Control-Request-Headers", "X-Got-Host")
+ })
+ require.NoError(t, err)
+ defer resp.Body.Close()
+
+ // Then: the request & response must match expectations
+ assert.Equal(t, tc.expectedStatusCode, resp.StatusCode)
+ assert.NoError(t, err)
+ if tc.checkRequestHeaders != nil {
+ tc.checkRequestHeaders(t, origin, reqHeaders)
+ }
+ tc.checkResponseHeaders(t, origin, resp.Header)
+ })
+ }
+ })
+
t.Run("WorkspaceApplicationAuth", func(t *testing.T) {
t.Parallel()
@@ -1389,7 +1783,7 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
forceURLTransport(t, client)
// Create workspace.
- port := appServer(t, nil, false)
+ port := appServer(t, nil, false, nil)
workspace, _ = createWorkspaceWithApps(t, client, user.OrganizationIDs[0], user, port, false)
// Verify that the apps have the correct sharing levels set.
@@ -1400,10 +1794,14 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
agnt = workspaceBuild.Resources[0].Agents[0]
found := map[string]codersdk.WorkspaceAppSharingLevel{}
expected := map[string]codersdk.WorkspaceAppSharingLevel{
- proxyTestAppNameFake: codersdk.WorkspaceAppSharingLevelOwner,
- proxyTestAppNameOwner: codersdk.WorkspaceAppSharingLevelOwner,
- proxyTestAppNameAuthenticated: codersdk.WorkspaceAppSharingLevelAuthenticated,
- proxyTestAppNamePublic: codersdk.WorkspaceAppSharingLevelPublic,
+ proxyTestAppNameFake: codersdk.WorkspaceAppSharingLevelOwner,
+ proxyTestAppNameOwner: codersdk.WorkspaceAppSharingLevelOwner,
+ proxyTestAppNameAuthenticated: codersdk.WorkspaceAppSharingLevelAuthenticated,
+ proxyTestAppNamePublic: codersdk.WorkspaceAppSharingLevelPublic,
+ proxyTestAppNameAuthenticatedCORSPassthru: codersdk.WorkspaceAppSharingLevelAuthenticated,
+ proxyTestAppNamePublicCORSPassthru: codersdk.WorkspaceAppSharingLevelPublic,
+ proxyTestAppNameAuthenticatedCORSDefault: codersdk.WorkspaceAppSharingLevelAuthenticated,
+ proxyTestAppNamePublicCORSDefault: codersdk.WorkspaceAppSharingLevelPublic,
}
for _, app := range agnt.Apps {
found[app.DisplayName] = app.SharingLevel
@@ -1560,6 +1958,12 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
// Unauthenticated user should not have any access.
verifyAccess(t, appDetails, isPathApp, user.Username, workspace.Name, agnt.Name, proxyTestAppNameAuthenticated, clientWithNoAuth, false, true)
+
+ // Unauthenticated user should not have any access, regardless of CORS behavior (using passthru).
+ verifyAccess(t, appDetails, isPathApp, user.Username, workspace.Name, agnt.Name, proxyTestAppNameAuthenticatedCORSPassthru, clientWithNoAuth, false, true)
+
+ // Unauthenticated user should not have any access, regardless of CORS behavior (using default).
+ verifyAccess(t, appDetails, isPathApp, user.Username, workspace.Name, agnt.Name, proxyTestAppNameAuthenticatedCORSDefault, clientWithNoAuth, false, true)
})
t.Run("LevelPublic", func(t *testing.T) {
@@ -1577,6 +1981,12 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
// Unauthenticated user should be able to access the workspace.
verifyAccess(t, appDetails, isPathApp, user.Username, workspace.Name, agnt.Name, proxyTestAppNamePublic, clientWithNoAuth, allowedUnlessSharingDisabled, !allowedUnlessSharingDisabled)
+
+ // Unauthenticated user should have access, regardless of CORS behavior (using passthru).
+ verifyAccess(t, appDetails, isPathApp, user.Username, workspace.Name, agnt.Name, proxyTestAppNamePublicCORSPassthru, clientWithNoAuth, allowedUnlessSharingDisabled, !allowedUnlessSharingDisabled)
+
+ // Unauthenticated user should have access, regardless of CORS behavior (using default).
+ verifyAccess(t, appDetails, isPathApp, user.Username, workspace.Name, agnt.Name, proxyTestAppNamePublicCORSDefault, clientWithNoAuth, allowedUnlessSharingDisabled, !allowedUnlessSharingDisabled)
})
}
@@ -1780,6 +2190,86 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
require.Equal(t, []string{"baz"}, resp.Header.Values("X-Foobar"))
})
+ // See above test for original implementation.
+ t.Run("CORSHeadersConditionallyStripped", func(t *testing.T) {
+ t.Parallel()
+
+ // Set a bunch of headers which may or may not be stripped, depending on the CORS behavior.
+ // See coderd/workspaceapps/proxy.go (proxyWorkspaceApp).
+ headers := http.Header{
+ "X-Foobar": []string{"baz"},
+ "Access-Control-Allow-Origin": []string{"http://localhost"},
+ "access-control-allow-origin": []string{"http://localhost"},
+ "Access-Control-Allow-Credentials": []string{"true"},
+ "Access-Control-Allow-Methods": []string{"PUT"},
+ "Access-Control-Allow-Headers": []string{"X-Foobar"},
+ }
+
+ appDetails := setupProxyTest(t, &DeploymentOptions{
+ headers: headers,
+ })
+
+ tests := []struct {
+ name string
+ app App
+ shouldStrip bool
+ }{
+ {
+ // Uses an app which does not set CORS behavior, which *should* be equivalent to default.
+ name: "NormalStrip",
+ app: appDetails.Apps.Owner,
+ shouldStrip: true,
+ },
+ {
+ // Explicitly uses the default CORS behavior.
+ name: "DefaultStrip",
+ app: appDetails.Apps.PublicCORSDefault,
+ shouldStrip: true,
+ },
+ {
+ // Explicitly does not strip CORS headers.
+ name: "PassthruNoStrip",
+ app: appDetails.Apps.PublicCORSPassthru,
+ shouldStrip: false,
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ ctx := testutil.Context(t, testutil.WaitLong)
+
+ // Given: a particular app
+ appURL := appDetails.SubdomainAppURL(tc.app)
+
+ // When: querying the app
+ resp, err := requestWithRetries(ctx, t, appDetails.AppClient(t), http.MethodGet, appURL.String(), nil)
+ require.NoError(t, err)
+ defer resp.Body.Close()
+
+ require.Equal(t, http.StatusOK, resp.StatusCode)
+
+ // Then: the CORS headers should be conditionally stripped or not, depending on the CORS behavior.
+ if tc.shouldStrip {
+ require.Empty(t, resp.Header.Values("Access-Control-Allow-Origin"))
+ require.Empty(t, resp.Header.Values("Access-Control-Allow-Credentials"))
+ require.Empty(t, resp.Header.Values("Access-Control-Allow-Methods"))
+ require.Empty(t, resp.Header.Values("Access-Control-Allow-Headers"))
+ } else {
+ for k, v := range headers {
+ // We dedupe the values because some headers have been set multiple times.
+ headerVal := dedupe(resp.Header.Values(k))
+ assert.ElementsMatchf(t, headerVal, v, "header %q does not contain %q", k, v)
+ }
+ }
+
+ // This header is not a CORS-related header, so it should always be set.
+ require.Equal(t, []string{"baz"}, resp.Header.Values("X-Foobar"))
+ })
+ }
+ })
+
t.Run("ReportStats", func(t *testing.T) {
t.Parallel()
@@ -2001,3 +2491,16 @@ func findCookie(cookies []*http.Cookie, name string) *http.Cookie {
}
return nil
}
+
+func dedupe[T comparable](elements []T) []T {
+ found := map[T]bool{}
+ result := []T{}
+
+ for _, v := range elements {
+ if !found[v] {
+ found[v] = true
+ result = append(result, v)
+ }
+ }
+ return result
+}
diff --git a/coderd/workspaceapps/apptest/setup.go b/coderd/workspaceapps/apptest/setup.go
index 9d1df9e7fe09d..98db937017853 100644
--- a/coderd/workspaceapps/apptest/setup.go
+++ b/coderd/workspaceapps/apptest/setup.go
@@ -36,8 +36,13 @@ const (
proxyTestAppNameOwner = "test-app-owner"
proxyTestAppNameAuthenticated = "test-app-authenticated"
proxyTestAppNamePublic = "test-app-public"
- proxyTestAppQuery = "query=true"
- proxyTestAppBody = "hello world from apps test"
+ // nolint:gosec // Not a secret
+ proxyTestAppNameAuthenticatedCORSPassthru = "test-app-authenticated-cors-passthru"
+ proxyTestAppNamePublicCORSPassthru = "test-app-public-cors-passthru"
+ proxyTestAppNameAuthenticatedCORSDefault = "test-app-authenticated-cors-default"
+ proxyTestAppNamePublicCORSDefault = "test-app-public-cors-default"
+ proxyTestAppQuery = "query=true"
+ proxyTestAppBody = "hello world from apps test"
proxyTestSubdomainRaw = "*.test.coder.com"
proxyTestSubdomain = "test.coder.com"
@@ -60,6 +65,7 @@ type DeploymentOptions struct {
noWorkspace bool
port uint16
headers http.Header
+ handler http.Handler
}
// Deployment is a license-agnostic deployment with all the fields that apps
@@ -93,6 +99,10 @@ type App struct {
// Prefix should have ---.
Prefix string
Query string
+ Path string
+
+ // Control the behavior of CORS handling.
+ CORSBehavior codersdk.AppCORSBehavior
}
// Details are the full test details returned from setupProxyTestWithFactory.
@@ -109,12 +119,16 @@ type Details struct {
AppPort uint16
Apps struct {
- Fake App
- Owner App
- Authenticated App
- Public App
- Port App
- PortHTTPS App
+ Fake App
+ Owner App
+ Authenticated App
+ Public App
+ Port App
+ PortHTTPS App
+ PublicCORSPassthru App
+ AuthenticatedCORSPassthru App
+ PublicCORSDefault App
+ AuthenticatedCORSDefault App
}
}
@@ -201,7 +215,7 @@ func setupProxyTestWithFactory(t *testing.T, factory DeploymentFactory, opts *De
}
if opts.port == 0 {
- opts.port = appServer(t, opts.headers, opts.ServeHTTPS)
+ opts.port = appServer(t, opts.headers, opts.ServeHTTPS, opts.handler)
}
workspace, agnt := createWorkspaceWithApps(t, deployment.SDKClient, deployment.FirstUser.OrganizationID, me, opts.port, opts.ServeHTTPS)
@@ -252,30 +266,64 @@ func setupProxyTestWithFactory(t *testing.T, factory DeploymentFactory, opts *De
AgentName: agnt.Name,
AppSlugOrPort: strconv.Itoa(int(opts.port)) + "s",
}
+ details.Apps.PublicCORSPassthru = App{
+ Username: me.Username,
+ WorkspaceName: workspace.Name,
+ AgentName: agnt.Name,
+ AppSlugOrPort: proxyTestAppNamePublicCORSPassthru,
+ CORSBehavior: codersdk.AppCORSBehaviorPassthru,
+ Query: proxyTestAppQuery,
+ }
+ details.Apps.AuthenticatedCORSPassthru = App{
+ Username: me.Username,
+ WorkspaceName: workspace.Name,
+ AgentName: agnt.Name,
+ AppSlugOrPort: proxyTestAppNameAuthenticatedCORSPassthru,
+ CORSBehavior: codersdk.AppCORSBehaviorPassthru,
+ Query: proxyTestAppQuery,
+ }
+ details.Apps.PublicCORSDefault = App{
+ Username: me.Username,
+ WorkspaceName: workspace.Name,
+ AgentName: agnt.Name,
+ AppSlugOrPort: proxyTestAppNamePublicCORSDefault,
+ Query: proxyTestAppQuery,
+ }
+ details.Apps.AuthenticatedCORSDefault = App{
+ Username: me.Username,
+ WorkspaceName: workspace.Name,
+ AgentName: agnt.Name,
+ AppSlugOrPort: proxyTestAppNameAuthenticatedCORSDefault,
+ Query: proxyTestAppQuery,
+ }
return details
}
//nolint:revive
-func appServer(t *testing.T, headers http.Header, isHTTPS bool) uint16 {
- server := httptest.NewUnstartedServer(
- http.HandlerFunc(
- func(w http.ResponseWriter, r *http.Request) {
- _, err := r.Cookie(codersdk.SessionTokenCookie)
- assert.ErrorIs(t, err, http.ErrNoCookie)
- w.Header().Set("X-Forwarded-For", r.Header.Get("X-Forwarded-For"))
- w.Header().Set("X-Got-Host", r.Host)
- for name, values := range headers {
- for _, value := range values {
- w.Header().Add(name, value)
- }
+func appServer(t *testing.T, headers http.Header, isHTTPS bool, handler http.Handler) uint16 {
+ defaultHandler := http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ _, err := r.Cookie(codersdk.SessionTokenCookie)
+ assert.ErrorIs(t, err, http.ErrNoCookie)
+ w.Header().Set("X-Forwarded-For", r.Header.Get("X-Forwarded-For"))
+ w.Header().Set("X-Got-Host", r.Host)
+ for name, values := range headers {
+ for _, value := range values {
+ w.Header().Add(name, value)
}
- w.WriteHeader(http.StatusOK)
- _, _ = w.Write([]byte(proxyTestAppBody))
- },
- ),
+ }
+ w.WriteHeader(http.StatusOK)
+ _, _ = w.Write([]byte(proxyTestAppBody))
+ },
)
+ if handler == nil {
+ handler = defaultHandler
+ }
+
+ server := httptest.NewUnstartedServer(handler)
+
server.Config.ReadHeaderTimeout = time.Minute
if isHTTPS {
server.StartTLS()
@@ -361,6 +409,36 @@ func createWorkspaceWithApps(t *testing.T, client *codersdk.Client, orgID uuid.U
Url: appURL,
Subdomain: true,
},
+ {
+ Slug: proxyTestAppNamePublicCORSPassthru,
+ DisplayName: proxyTestAppNamePublicCORSPassthru,
+ SharingLevel: proto.AppSharingLevel_PUBLIC,
+ Url: appURL,
+ Subdomain: true,
+ CorsBehavior: proto.AppCORSBehavior_PASSTHRU,
+ },
+ {
+ Slug: proxyTestAppNameAuthenticatedCORSPassthru,
+ DisplayName: proxyTestAppNameAuthenticatedCORSPassthru,
+ SharingLevel: proto.AppSharingLevel_AUTHENTICATED,
+ Url: appURL,
+ Subdomain: true,
+ CorsBehavior: proto.AppCORSBehavior_PASSTHRU,
+ },
+ {
+ Slug: proxyTestAppNamePublicCORSDefault,
+ DisplayName: proxyTestAppNamePublicCORSDefault,
+ SharingLevel: proto.AppSharingLevel_PUBLIC,
+ Url: appURL,
+ Subdomain: true,
+ },
+ {
+ Slug: proxyTestAppNameAuthenticatedCORSDefault,
+ DisplayName: proxyTestAppNameAuthenticatedCORSDefault,
+ SharingLevel: proto.AppSharingLevel_AUTHENTICATED,
+ Url: appURL,
+ Subdomain: true,
+ },
}
version := coderdtest.CreateTemplateVersion(t, client, orgID, &echo.Responses{
Parse: echo.ParseComplete,
diff --git a/coderd/workspaceapps/cors/cors.go b/coderd/workspaceapps/cors/cors.go
new file mode 100644
index 0000000000000..c204cb322f173
--- /dev/null
+++ b/coderd/workspaceapps/cors/cors.go
@@ -0,0 +1,21 @@
+package cors
+
+import (
+ "context"
+
+ "github.com/coder/coder/v2/codersdk"
+)
+
+type contextKeyBehavior struct{}
+
+// WithBehavior sets the CORS behavior for the given context.
+func WithBehavior(ctx context.Context, behavior codersdk.AppCORSBehavior) context.Context {
+ return context.WithValue(ctx, contextKeyBehavior{}, behavior)
+}
+
+// HasBehavior returns true if the given context has the specified CORS behavior.
+func HasBehavior(ctx context.Context, behavior codersdk.AppCORSBehavior) bool {
+ val := ctx.Value(contextKeyBehavior{})
+ b, ok := val.(codersdk.AppCORSBehavior)
+ return ok && b == behavior
+}
diff --git a/coderd/workspaceapps/db.go b/coderd/workspaceapps/db.go
index 90c6f107daa5e..9234e304c1162 100644
--- a/coderd/workspaceapps/db.go
+++ b/coderd/workspaceapps/db.go
@@ -152,6 +152,7 @@ func (p *DBTokenProvider) Issue(ctx context.Context, rw http.ResponseWriter, r *
if dbReq.AppURL != nil {
token.AppURL = dbReq.AppURL.String()
}
+ token.CORSBehavior = codersdk.AppCORSBehavior(dbReq.AppCORSBehavior)
// Verify the user has access to the app.
authed, warnings, err := p.authorizeRequest(r.Context(), authz, dbReq)
diff --git a/coderd/workspaceapps/db_test.go b/coderd/workspaceapps/db_test.go
index 597d1daadfa54..720685ae9a922 100644
--- a/coderd/workspaceapps/db_test.go
+++ b/coderd/workspaceapps/db_test.go
@@ -320,11 +320,12 @@ func Test_ResolveRequest(t *testing.T) {
RegisteredClaims: jwtutils.RegisteredClaims{
Expiry: jwt.NewNumericDate(token.Expiry.Time()),
},
- Request: req,
- UserID: me.ID,
- WorkspaceID: workspace.ID,
- AgentID: agentID,
- AppURL: appURL,
+ Request: req,
+ UserID: me.ID,
+ WorkspaceID: workspace.ID,
+ AgentID: agentID,
+ AppURL: appURL,
+ CORSBehavior: token.CORSBehavior,
}, token)
require.NotZero(t, token.Expiry)
require.WithinDuration(t, time.Now().Add(workspaceapps.DefaultTokenExpiry), token.Expiry.Time(), time.Minute)
diff --git a/coderd/workspaceapps/provider.go b/coderd/workspaceapps/provider.go
index 1cd652976f6f4..aa2515ffb4605 100644
--- a/coderd/workspaceapps/provider.go
+++ b/coderd/workspaceapps/provider.go
@@ -7,6 +7,7 @@ import (
"time"
"cdr.dev/slog"
+
"github.com/coder/coder/v2/codersdk"
)
diff --git a/coderd/workspaceapps/proxy.go b/coderd/workspaceapps/proxy.go
index bc8d32ed2ead9..907803679b713 100644
--- a/coderd/workspaceapps/proxy.go
+++ b/coderd/workspaceapps/proxy.go
@@ -28,6 +28,7 @@ import (
"github.com/coder/coder/v2/coderd/tracing"
"github.com/coder/coder/v2/coderd/util/slice"
"github.com/coder/coder/v2/coderd/workspaceapps/appurl"
+ "github.com/coder/coder/v2/coderd/workspaceapps/cors"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/codersdk/workspacesdk"
"github.com/coder/coder/v2/site"
@@ -394,36 +395,38 @@ func (s *Server) HandleSubdomain(middlewares ...func(http.Handler) http.Handler)
return
}
+ // Cookie smuggling needs to happen before CORs behavior is determined.
+ if !s.handleAPIKeySmuggling(rw, r, AccessMethodSubdomain) {
+ return
+ }
+
+ token, ok := ResolveRequest(rw, r, ResolveRequestOptions{
+ Logger: s.Logger,
+ CookieCfg: s.Cookies,
+ SignedTokenProvider: s.SignedTokenProvider,
+ DashboardURL: s.DashboardURL,
+ PathAppBaseURL: s.AccessURL,
+ AppHostname: s.Hostname,
+ AppRequest: Request{
+ AccessMethod: AccessMethodSubdomain,
+ BasePath: "/",
+ Prefix: app.Prefix,
+ UsernameOrID: app.Username,
+ WorkspaceNameOrID: app.WorkspaceName,
+ AgentNameOrID: app.AgentName,
+ AppSlugOrPort: app.AppSlugOrPort,
+ },
+ AppPath: r.URL.Path,
+ AppQuery: r.URL.RawQuery,
+ })
+ if !ok {
+ return
+ }
+
// Use the passed in app middlewares before checking authentication and
// passing to the proxy app.
- mws := chi.Middlewares(append(middlewares, httpmw.WorkspaceAppCors(s.HostnameRegex, app)))
+ mws := chi.Middlewares(append(middlewares, s.determineCORSBehavior(token, app)))
mws.Handler(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
- if !s.handleAPIKeySmuggling(rw, r, AccessMethodSubdomain) {
- return
- }
-
- token, ok := ResolveRequest(rw, r, ResolveRequestOptions{
- Logger: s.Logger,
- CookieCfg: s.Cookies,
- SignedTokenProvider: s.SignedTokenProvider,
- DashboardURL: s.DashboardURL,
- PathAppBaseURL: s.AccessURL,
- AppHostname: s.Hostname,
- AppRequest: Request{
- AccessMethod: AccessMethodSubdomain,
- BasePath: "/",
- Prefix: app.Prefix,
- UsernameOrID: app.Username,
- WorkspaceNameOrID: app.WorkspaceName,
- AgentNameOrID: app.AgentName,
- AppSlugOrPort: app.AppSlugOrPort,
- },
- AppPath: r.URL.Path,
- AppQuery: r.URL.RawQuery,
- })
- if !ok {
- return
- }
s.proxyWorkspaceApp(rw, r, *token, r.URL.Path, app)
})).ServeHTTP(rw, r.WithContext(ctx))
})
@@ -560,6 +563,11 @@ func (s *Server) proxyWorkspaceApp(rw http.ResponseWriter, r *http.Request, appT
proxy := s.AgentProvider.ReverseProxy(appURL, s.DashboardURL, appToken.AgentID, app, s.Hostname)
proxy.ModifyResponse = func(r *http.Response) error {
+ // If passthru behavior is set, disable our CORS header stripping.
+ if cors.HasBehavior(r.Request.Context(), codersdk.AppCORSBehaviorPassthru) {
+ return nil
+ }
+
r.Header.Del(httpmw.AccessControlAllowOriginHeader)
r.Header.Del(httpmw.AccessControlAllowCredentialsHeader)
r.Header.Del(httpmw.AccessControlAllowMethodsHeader)
@@ -765,3 +773,34 @@ func WebsocketNetConn(ctx context.Context, conn *websocket.Conn, msgType websock
Conn: nc,
}
}
+
+// determineCORSBehavior examines the given token and conditionally applies
+// CORS middleware if the token specifies that behavior.
+func (s *Server) determineCORSBehavior(token *SignedToken, app appurl.ApplicationURL) func(http.Handler) http.Handler {
+ return func(next http.Handler) http.Handler {
+ // Create the CORS middleware handler upfront.
+ corsHandler := httpmw.WorkspaceAppCors(s.HostnameRegex, app)(next)
+
+ return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+ var behavior codersdk.AppCORSBehavior
+ if token != nil {
+ behavior = token.CORSBehavior
+ }
+
+ // Add behavior to context regardless of which handler we use,
+ // since we will use this later on to determine if we should strip
+ // CORS headers in the response.
+ r = r.WithContext(cors.WithBehavior(r.Context(), behavior))
+
+ switch behavior {
+ case codersdk.AppCORSBehaviorPassthru:
+ // Bypass the CORS middleware.
+ next.ServeHTTP(rw, r)
+ return
+ default:
+ // Apply the CORS middleware.
+ corsHandler.ServeHTTP(rw, r)
+ }
+ })
+ }
+}
diff --git a/coderd/workspaceapps/request.go b/coderd/workspaceapps/request.go
index 0e6a43cb4cbe4..aabca1a648f0b 100644
--- a/coderd/workspaceapps/request.go
+++ b/coderd/workspaceapps/request.go
@@ -204,6 +204,8 @@ type databaseRequest struct {
// AppSharingLevel is the sharing level of the app. This is forced to be set
// to AppSharingLevelOwner if the access method is terminal.
AppSharingLevel database.AppSharingLevel
+ // AppCORSBehavior defines the behavior of the CORS middleware.
+ AppCORSBehavior database.AppCORSBehavior
}
// getDatabase does queries to get the owner user, workspace and agent
@@ -293,12 +295,16 @@ func (r Request) getDatabase(ctx context.Context, db database.Store) (*databaseR
app database.WorkspaceApp
appURL string
appSharingLevel database.AppSharingLevel
+ appCORSBehavior database.AppCORSBehavior
// First check if it's a port-based URL with an optional "s" suffix for HTTPS.
potentialPortStr = strings.TrimSuffix(r.AppSlugOrPort, "s")
portUint, portUintErr = strconv.ParseUint(potentialPortStr, 10, 16)
)
//nolint:nestif
if portUintErr == nil {
+ // TODO: handle CORS passthru for port sharing use-case.
+ appCORSBehavior = database.AppCorsBehaviorSimple
+
protocol := "http"
if strings.HasSuffix(r.AppSlugOrPort, "s") {
protocol = "https"
@@ -370,6 +376,7 @@ func (r Request) getDatabase(ctx context.Context, db database.Store) (*databaseR
appSharingLevel = database.AppSharingLevelOwner
}
appURL = app.Url.String
+ appCORSBehavior = app.CORSBehavior
break
}
}
@@ -417,6 +424,7 @@ func (r Request) getDatabase(ctx context.Context, db database.Store) (*databaseR
App: app,
AppURL: appURLParsed,
AppSharingLevel: appSharingLevel,
+ AppCORSBehavior: appCORSBehavior,
}, nil
}
diff --git a/coderd/workspaceapps/token.go b/coderd/workspaceapps/token.go
index dcd8c5a0e5c34..d46f7b9335212 100644
--- a/coderd/workspaceapps/token.go
+++ b/coderd/workspaceapps/token.go
@@ -22,10 +22,11 @@ type SignedToken struct {
// Request details.
Request `json:"request"`
- UserID uuid.UUID `json:"user_id"`
- WorkspaceID uuid.UUID `json:"workspace_id"`
- AgentID uuid.UUID `json:"agent_id"`
- AppURL string `json:"app_url"`
+ UserID uuid.UUID `json:"user_id"`
+ WorkspaceID uuid.UUID `json:"workspace_id"`
+ AgentID uuid.UUID `json:"agent_id"`
+ AppURL string `json:"app_url"`
+ CORSBehavior codersdk.AppCORSBehavior `json:"cors_behavior"`
}
// MatchesRequest returns true if the token matches the request. Any token that
diff --git a/codersdk/cors_behavior.go b/codersdk/cors_behavior.go
new file mode 100644
index 0000000000000..8fd8b9a893e37
--- /dev/null
+++ b/codersdk/cors_behavior.go
@@ -0,0 +1,17 @@
+package codersdk
+
+import "golang.org/x/xerrors"
+
+type AppCORSBehavior string
+
+const (
+ AppCORSBehaviorSimple AppCORSBehavior = "simple"
+ AppCORSBehaviorPassthru AppCORSBehavior = "passthru"
+)
+
+func (c AppCORSBehavior) Validate() error {
+ if c != AppCORSBehaviorSimple && c != AppCORSBehaviorPassthru {
+ return xerrors.New("Invalid CORS behavior.")
+ }
+ return nil
+}
diff --git a/docs/admin/security/audit-logs.md b/docs/admin/security/audit-logs.md
index c9124efa14bf0..f0fdc1ab68461 100644
--- a/docs/admin/security/audit-logs.md
+++ b/docs/admin/security/audit-logs.md
@@ -30,7 +30,7 @@ We track the following resources:
| TemplateVersion
create, write |
Field | Tracked |
| archived | true |
created_at | false |
created_by | true |
created_by_avatar_url | false |
created_by_username | false |
external_auth_providers | false |
id | true |
job_id | false |
message | false |
name | true |
organization_id | false |
readme | true |
source_example_id | false |
template_id | true |
updated_at | false |
|
| User
create, write, delete | Field | Tracked |
| avatar_url | false |
created_at | false |
deleted | true |
email | true |
github_com_user_id | false |
hashed_one_time_passcode | false |
hashed_password | true |
id | true |
is_system | true |
last_seen_at | false |
login_type | true |
name | true |
one_time_passcode_expires_at | true |
quiet_hours_schedule | true |
rbac_roles | true |
status | true |
updated_at | false |
username | true |
|
| WorkspaceAgent
connect, disconnect | Field | Tracked |
| api_version | false |
architecture | false |
auth_instance_id | false |
auth_token | false |
connection_timeout_seconds | false |
created_at | false |
directory | false |
disconnected_at | false |
display_apps | false |
display_order | false |
environment_variables | false |
expanded_directory | false |
first_connected_at | false |
id | false |
instance_metadata | false |
last_connected_at | false |
last_connected_replica_id | false |
lifecycle_state | false |
logs_length | false |
logs_overflowed | false |
motd_file | false |
name | false |
operating_system | false |
ready_at | false |
resource_id | false |
resource_metadata | false |
started_at | false |
subsystems | false |
troubleshooting_url | false |
updated_at | false |
version | false |
|
-| WorkspaceApp
open, close | Field | Tracked |
| agent_id | false |
command | false |
created_at | false |
display_name | false |
display_order | false |
external | false |
health | false |
healthcheck_interval | false |
healthcheck_threshold | false |
healthcheck_url | false |
hidden | false |
icon | false |
id | false |
open_in | false |
sharing_level | false |
slug | false |
subdomain | false |
url | false |
|
+| WorkspaceApp
open, close | Field | Tracked |
| agent_id | false |
command | false |
cors_behavior | false |
created_at | false |
display_name | false |
display_order | false |
external | false |
health | false |
healthcheck_interval | false |
healthcheck_threshold | false |
healthcheck_url | false |
hidden | false |
icon | false |
id | false |
open_in | false |
sharing_level | false |
slug | false |
subdomain | false |
url | false |
|
| WorkspaceBuild
start, stop | Field | Tracked |
| build_number | false |
created_at | false |
daily_cost | false |
deadline | false |
id | false |
initiator_by_avatar_url | false |
initiator_by_username | false |
initiator_id | false |
job_id | false |
max_deadline | false |
provisioner_state | false |
reason | false |
template_version_id | true |
template_version_preset_id | false |
transition | false |
updated_at | false |
workspace_id | false |
|
| WorkspaceProxy
| Field | Tracked |
| created_at | true |
deleted | false |
derp_enabled | true |
derp_only | true |
display_name | true |
icon | true |
id | true |
name | true |
region_id | true |
token_hashed_secret | true |
updated_at | false |
url | true |
version | true |
wildcard_hostname | true |
|
| WorkspaceTable
| Field | Tracked |
| automatic_updates | true |
autostart_schedule | true |
created_at | false |
deleted | false |
deleting_at | true |
dormant_at | true |
favorite | true |
id | true |
last_used_at | false |
name | true |
next_start_at | true |
organization_id | false |
owner_id | true |
template_id | true |
ttl | true |
updated_at | false |
|
diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go
index 84cc7d451b4f1..546824f9cd245 100644
--- a/enterprise/audit/table.go
+++ b/enterprise/audit/table.go
@@ -362,6 +362,7 @@ var auditableResourcesTypes = map[any]map[string]Action{
"display_order": ActionIgnore,
"hidden": ActionIgnore,
"open_in": ActionIgnore,
+ "cors_behavior": ActionIgnore,
},
}
diff --git a/enterprise/wsproxy/wsproxy.go b/enterprise/wsproxy/wsproxy.go
index bce49417fcd35..69241d8aa1c17 100644
--- a/enterprise/wsproxy/wsproxy.go
+++ b/enterprise/wsproxy/wsproxy.go
@@ -339,11 +339,11 @@ func New(ctx context.Context, opts *Options) (*Server, error) {
httpmw.ExtractRealIP(s.Options.RealIPConfig),
loggermw.Logger(s.Logger),
prometheusMW,
- corsMW,
// HandleSubdomain is a middleware that handles all requests to the
// subdomain-based workspace apps.
s.AppServer.HandleSubdomain(apiRateLimiter),
+ corsMW,
// Build-Version is helpful for debugging.
func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
diff --git a/examples/cors_demo/main.go b/examples/cors_demo/main.go
new file mode 100644
index 0000000000000..95b3e2008e649
--- /dev/null
+++ b/examples/cors_demo/main.go
@@ -0,0 +1,79 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "html/template"
+ "log"
+ "net/http"
+)
+
+var enableCORS bool
+var port int
+
+func main() {
+ flag.IntVar(&port, "port", 7600, "Port to run the server on")
+ flag.BoolVar(&enableCORS, "cors", false, "Enable CORS headers")
+ flag.Parse()
+
+ http.HandleFunc("/", serveHTML)
+ http.HandleFunc("/test", testHandler)
+
+ fmt.Printf("Server started at :%d\n", port)
+ log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
+}
+
+func serveHTML(w http.ResponseWriter, r *http.Request) {
+ if enableCORS {
+ w.Header().Set("Access-Control-Allow-Origin", "*")
+ }
+ tmpl := `
+
+
+
+ Fetch Test
+
+
+ Fetch Tester
+
+
+
+
+
+
+
+
+ `
+ t := template.Must(template.New("page").Parse(tmpl))
+ t.Execute(w, nil)
+}
+
+func testHandler(w http.ResponseWriter, r *http.Request) {
+ if enableCORS {
+ w.Header().Set("Access-Control-Allow-Origin", "*")
+ }
+ fmt.Fprintf(w, "You made a %s request to /test", r.Method)
+}
diff --git a/provisioner/terraform/resources.go b/provisioner/terraform/resources.go
index da86ab2f3d48e..264e278d60ae7 100644
--- a/provisioner/terraform/resources.go
+++ b/provisioner/terraform/resources.go
@@ -98,17 +98,18 @@ type agentAppAttributes struct {
Slug string `mapstructure:"slug"`
DisplayName string `mapstructure:"display_name"`
// Name is deprecated in favor of DisplayName.
- Name string `mapstructure:"name"`
- Icon string `mapstructure:"icon"`
- URL string `mapstructure:"url"`
- External bool `mapstructure:"external"`
- Command string `mapstructure:"command"`
- Share string `mapstructure:"share"`
- Subdomain bool `mapstructure:"subdomain"`
- Healthcheck []appHealthcheckAttributes `mapstructure:"healthcheck"`
- Order int64 `mapstructure:"order"`
- Hidden bool `mapstructure:"hidden"`
- OpenIn string `mapstructure:"open_in"`
+ Name string `mapstructure:"name"`
+ Icon string `mapstructure:"icon"`
+ URL string `mapstructure:"url"`
+ External bool `mapstructure:"external"`
+ Command string `mapstructure:"command"`
+ Share string `mapstructure:"share"`
+ Subdomain bool `mapstructure:"subdomain"`
+ Healthcheck []appHealthcheckAttributes `mapstructure:"healthcheck"`
+ Order int64 `mapstructure:"order"`
+ Hidden bool `mapstructure:"hidden"`
+ OpenIn string `mapstructure:"open_in"`
+ CORSBehavior string `mapstructure:"cors_behavior"`
}
type agentEnvAttributes struct {
@@ -511,6 +512,15 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s
openIn = proto.AppOpenIn_TAB
}
+ var corsBehavior proto.AppCORSBehavior
+ switch strings.ToLower(attrs.CORSBehavior) {
+ case "passthru":
+ corsBehavior = proto.AppCORSBehavior_PASSTHRU
+ default:
+ corsBehavior = proto.AppCORSBehavior_SIMPLE
+ logger.Debug(ctx, "cors_behavior not set, defaulting to 'simple'", slog.F("address", convertAddressToLabel(resource.Address)))
+ }
+
for _, agents := range resourceAgents {
for _, agent := range agents {
// Find agents with the matching ID and associate them!
@@ -532,6 +542,7 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s
Order: attrs.Order,
Hidden: attrs.Hidden,
OpenIn: openIn,
+ CorsBehavior: corsBehavior,
})
}
}
diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go
index f258f79e36f94..ab6acbf6c2724 100644
--- a/provisionersdk/proto/provisioner.pb.go
+++ b/provisionersdk/proto/provisioner.pb.go
@@ -126,6 +126,52 @@ func (AppSharingLevel) EnumDescriptor() ([]byte, []int) {
return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{1}
}
+type AppCORSBehavior int32
+
+const (
+ AppCORSBehavior_SIMPLE AppCORSBehavior = 0
+ AppCORSBehavior_PASSTHRU AppCORSBehavior = 1
+)
+
+// Enum value maps for AppCORSBehavior.
+var (
+ AppCORSBehavior_name = map[int32]string{
+ 0: "SIMPLE",
+ 1: "PASSTHRU",
+ }
+ AppCORSBehavior_value = map[string]int32{
+ "SIMPLE": 0,
+ "PASSTHRU": 1,
+ }
+)
+
+func (x AppCORSBehavior) Enum() *AppCORSBehavior {
+ p := new(AppCORSBehavior)
+ *p = x
+ return p
+}
+
+func (x AppCORSBehavior) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (AppCORSBehavior) Descriptor() protoreflect.EnumDescriptor {
+ return file_provisionersdk_proto_provisioner_proto_enumTypes[2].Descriptor()
+}
+
+func (AppCORSBehavior) Type() protoreflect.EnumType {
+ return &file_provisionersdk_proto_provisioner_proto_enumTypes[2]
+}
+
+func (x AppCORSBehavior) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use AppCORSBehavior.Descriptor instead.
+func (AppCORSBehavior) EnumDescriptor() ([]byte, []int) {
+ return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{2}
+}
+
type AppOpenIn int32
const (
@@ -160,11 +206,11 @@ func (x AppOpenIn) String() string {
}
func (AppOpenIn) Descriptor() protoreflect.EnumDescriptor {
- return file_provisionersdk_proto_provisioner_proto_enumTypes[2].Descriptor()
+ return file_provisionersdk_proto_provisioner_proto_enumTypes[3].Descriptor()
}
func (AppOpenIn) Type() protoreflect.EnumType {
- return &file_provisionersdk_proto_provisioner_proto_enumTypes[2]
+ return &file_provisionersdk_proto_provisioner_proto_enumTypes[3]
}
func (x AppOpenIn) Number() protoreflect.EnumNumber {
@@ -173,7 +219,7 @@ func (x AppOpenIn) Number() protoreflect.EnumNumber {
// Deprecated: Use AppOpenIn.Descriptor instead.
func (AppOpenIn) EnumDescriptor() ([]byte, []int) {
- return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{2}
+ return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{3}
}
// WorkspaceTransition is the desired outcome of a build
@@ -210,11 +256,11 @@ func (x WorkspaceTransition) String() string {
}
func (WorkspaceTransition) Descriptor() protoreflect.EnumDescriptor {
- return file_provisionersdk_proto_provisioner_proto_enumTypes[3].Descriptor()
+ return file_provisionersdk_proto_provisioner_proto_enumTypes[4].Descriptor()
}
func (WorkspaceTransition) Type() protoreflect.EnumType {
- return &file_provisionersdk_proto_provisioner_proto_enumTypes[3]
+ return &file_provisionersdk_proto_provisioner_proto_enumTypes[4]
}
func (x WorkspaceTransition) Number() protoreflect.EnumNumber {
@@ -223,7 +269,7 @@ func (x WorkspaceTransition) Number() protoreflect.EnumNumber {
// Deprecated: Use WorkspaceTransition.Descriptor instead.
func (WorkspaceTransition) EnumDescriptor() ([]byte, []int) {
- return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{3}
+ return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{4}
}
type TimingState int32
@@ -259,11 +305,11 @@ func (x TimingState) String() string {
}
func (TimingState) Descriptor() protoreflect.EnumDescriptor {
- return file_provisionersdk_proto_provisioner_proto_enumTypes[4].Descriptor()
+ return file_provisionersdk_proto_provisioner_proto_enumTypes[5].Descriptor()
}
func (TimingState) Type() protoreflect.EnumType {
- return &file_provisionersdk_proto_provisioner_proto_enumTypes[4]
+ return &file_provisionersdk_proto_provisioner_proto_enumTypes[5]
}
func (x TimingState) Number() protoreflect.EnumNumber {
@@ -272,7 +318,7 @@ func (x TimingState) Number() protoreflect.EnumNumber {
// Deprecated: Use TimingState.Descriptor instead.
func (TimingState) EnumDescriptor() ([]byte, []int) {
- return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{4}
+ return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{5}
}
// Empty indicates a successful request/response.
@@ -1866,6 +1912,7 @@ type App struct {
Order int64 `protobuf:"varint,10,opt,name=order,proto3" json:"order,omitempty"`
Hidden bool `protobuf:"varint,11,opt,name=hidden,proto3" json:"hidden,omitempty"`
OpenIn AppOpenIn `protobuf:"varint,12,opt,name=open_in,json=openIn,proto3,enum=provisioner.AppOpenIn" json:"open_in,omitempty"`
+ CorsBehavior AppCORSBehavior `protobuf:"varint,13,opt,name=cors_behavior,json=corsBehavior,proto3,enum=provisioner.AppCORSBehavior" json:"cors_behavior,omitempty"`
}
func (x *App) Reset() {
@@ -1984,6 +2031,13 @@ func (x *App) GetOpenIn() AppOpenIn {
return AppOpenIn_WINDOW
}
+func (x *App) GetCorsBehavior() AppCORSBehavior {
+ if x != nil {
+ return x.CorsBehavior
+ }
+ return AppCORSBehavior_SIMPLE
+}
+
// Healthcheck represents configuration for checking for app readiness.
type Healthcheck struct {
state protoimpl.MessageState
@@ -3739,7 +3793,7 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{
0x61, 0x63, 0x65, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
- 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x94,
+ 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xd7,
0x03, 0x0a, 0x03, 0x41, 0x70, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69,
0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
@@ -3765,269 +3819,276 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{
0x64, 0x64, 0x65, 0x6e, 0x12, 0x2f, 0x0a, 0x07, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x69, 0x6e, 0x18,
0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f,
0x6e, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x4f, 0x70, 0x65, 0x6e, 0x49, 0x6e, 0x52, 0x06, 0x6f,
- 0x70, 0x65, 0x6e, 0x49, 0x6e, 0x22, 0x59, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63,
- 0x68, 0x65, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76,
- 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76,
- 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18,
- 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64,
- 0x22, 0x92, 0x03, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a,
- 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
- 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18,
- 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f,
- 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74,
- 0x73, 0x12, 0x3a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20,
- 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65,
- 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64,
- 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a,
- 0x04, 0x68, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x68, 0x69, 0x64,
- 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
- 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e,
- 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61,
- 0x69, 0x6c, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09,
- 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64,
- 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
- 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x1a, 0x69, 0x0a, 0x08, 0x4d, 0x65,
- 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 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, 0x12, 0x1c,
- 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
- 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x12, 0x17, 0x0a, 0x07,
- 0x69, 0x73, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69,
- 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x22, 0x4c, 0x0a, 0x06, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12,
- 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
- 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
- 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
- 0x6b, 0x65, 0x79, 0x22, 0x31, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e,
- 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
- 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
- 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x22, 0xe0, 0x08, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64,
- 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c,
- 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x55, 0x72, 0x6c,
- 0x12, 0x53, 0x0a, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x72,
- 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20,
- 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72,
- 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,
- 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73,
- 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77,
- 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f,
- 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18,
- 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65,
- 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x77, 0x6f, 0x72,
- 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b,
- 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x06,
- 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f,
- 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70,
- 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18,
- 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65,
- 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x65,
- 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x0c, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12,
- 0x29, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73,
- 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x65, 0x6d, 0x70, 0x6c,
- 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x48, 0x0a, 0x21, 0x77, 0x6f,
- 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6f, 0x69,
- 0x64, 0x63, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18,
- 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65,
- 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4f, 0x69, 0x64, 0x63, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54,
- 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x41, 0x0a, 0x1d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
- 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, 0x77, 0x6f, 0x72,
- 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69,
- 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x6c,
- 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x65,
- 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x77, 0x6f, 0x72, 0x6b,
- 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
- 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x77, 0x6f,
- 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x67, 0x72,
- 0x6f, 0x75, 0x70, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x77, 0x6f, 0x72, 0x6b,
- 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73,
- 0x12, 0x42, 0x0a, 0x1e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77,
- 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b,
- 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70,
- 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x53, 0x73, 0x68, 0x50, 0x75, 0x62, 0x6c, 0x69,
- 0x63, 0x4b, 0x65, 0x79, 0x12, 0x44, 0x0a, 0x1f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x70, 0x72, 0x69, 0x76,
- 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1b, 0x77,
- 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x53, 0x73, 0x68,
- 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x12, 0x77, 0x6f,
- 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64,
- 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x3b, 0x0a, 0x1a, 0x77, 0x6f, 0x72, 0x6b,
- 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x69,
- 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x77, 0x6f,
- 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x69,
- 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x4e, 0x0a, 0x1a, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
- 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x72, 0x62, 0x61, 0x63, 0x5f, 0x72, 0x6f,
- 0x6c, 0x65, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x76,
- 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x17, 0x77, 0x6f,
- 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x52, 0x62, 0x61, 0x63,
- 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x62,
- 0x75, 0x69, 0x6c, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x73, 0x50, 0x72,
- 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x41, 0x0a, 0x1d, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e,
- 0x67, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x61, 0x67, 0x65, 0x6e,
- 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, 0x72,
- 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x41,
- 0x67, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x8a, 0x01, 0x0a, 0x06, 0x43, 0x6f,
- 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x17, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65,
- 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x18,
- 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x53,
- 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05,
- 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61,
- 0x74, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65,
- 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28,
- 0x09, 0x52, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x4c, 0x6f,
- 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x0e, 0x0a, 0x0c, 0x50, 0x61, 0x72, 0x73, 0x65, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xa3, 0x02, 0x0a, 0x0d, 0x50, 0x61, 0x72, 0x73, 0x65,
- 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, 0x4c,
- 0x0a, 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61,
- 0x62, 0x6c, 0x65, 0x73, 0x18, 0x02, 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, 0x16, 0x0a, 0x06,
- 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65,
- 0x61, 0x64, 0x6d, 0x65, 0x12, 0x54, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63,
- 0x65, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 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, 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, 0x22, 0xb5, 0x02, 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, 0x22, 0x99, 0x03, 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, 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, 0x3a, 0x0a, 0x0a, 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, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x61, 0x0a, 0x17,
+ 0x70, 0x65, 0x6e, 0x49, 0x6e, 0x12, 0x41, 0x0a, 0x0d, 0x63, 0x6f, 0x72, 0x73, 0x5f, 0x62, 0x65,
+ 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x70,
+ 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x43, 0x4f,
+ 0x52, 0x53, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x52, 0x0c, 0x63, 0x6f, 0x72, 0x73,
+ 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x22, 0x59, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x6c,
+ 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x74,
+ 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x69, 0x6e, 0x74,
+ 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f,
+ 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68,
+ 0x6f, 0x6c, 0x64, 0x22, 0x92, 0x03, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
+ 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+ 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e,
+ 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69,
+ 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x67,
+ 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69,
+ 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+ 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04,
+ 0x68, 0x69, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x74,
+ 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a,
+ 0x0a, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28,
+ 0x05, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b,
+ 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x1a, 0x69, 0x0a,
+ 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 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, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03,
+ 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x12,
+ 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08,
+ 0x52, 0x06, 0x69, 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x22, 0x4c, 0x0a, 0x06, 0x4d, 0x6f, 0x64, 0x75,
+ 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65,
+ 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72,
+ 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x31, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x12,
+ 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
+ 0x6d, 0x65, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x22, 0xe0, 0x08, 0x0a, 0x08, 0x4d, 0x65,
+ 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f,
+ 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x72,
+ 0x55, 0x72, 0x6c, 0x12, 0x53, 0x0a, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65,
+ 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x0e, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e,
+ 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74,
+ 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72,
+ 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12,
+ 0x27, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e,
+ 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70,
+ 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
+ 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x77,
+ 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69,
+ 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
+ 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x77, 0x6f, 0x72,
+ 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61,
+ 0x69, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70,
+ 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x23, 0x0a,
+ 0x0d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x4e, 0x61,
+ 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76,
+ 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x65,
+ 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x48, 0x0a,
+ 0x21, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72,
+ 0x5f, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b,
+ 0x65, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70,
+ 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4f, 0x69, 0x64, 0x63, 0x41, 0x63, 0x63, 0x65,
+ 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x41, 0x0a, 0x1d, 0x77, 0x6f, 0x72, 0x6b, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69,
+ 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a,
+ 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x53, 0x65,
+ 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x65,
+ 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x0a, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x77,
+ 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6e,
+ 0x61, 0x6d, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x34, 0x0a,
+ 0x16, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72,
+ 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x77,
+ 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x47, 0x72, 0x6f,
+ 0x75, 0x70, 0x73, 0x12, 0x42, 0x0a, 0x1e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65,
+ 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69,
+ 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, 0x77, 0x6f, 0x72,
+ 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x53, 0x73, 0x68, 0x50, 0x75,
+ 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x44, 0x0a, 0x1f, 0x77, 0x6f, 0x72, 0x6b, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x70,
+ 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x1b, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72,
+ 0x53, 0x73, 0x68, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x2c, 0x0a,
+ 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
+ 0x5f, 0x69, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x12, 0x3b, 0x0a, 0x1a, 0x77,
+ 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6c,
+ 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x17, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4c,
+ 0x6f, 0x67, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x4e, 0x0a, 0x1a, 0x77, 0x6f, 0x72, 0x6b,
+ 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x72, 0x62, 0x61, 0x63,
+ 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70,
+ 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x52,
+ 0x17, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x52,
+ 0x62, 0x61, 0x63, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x70,
+ 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69,
+ 0x73, 0x50, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x41, 0x0a, 0x1d, 0x72, 0x75, 0x6e,
+ 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x61,
+ 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09,
+ 0x52, 0x1a, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61,
+ 0x63, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x8a, 0x01, 0x0a,
+ 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x17, 0x74, 0x65, 0x6d, 0x70, 0x6c,
+ 0x61, 0x74, 0x65, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69,
+ 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61,
+ 0x74, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x12,
+ 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05,
+ 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69,
+ 0x6f, 0x6e, 0x65, 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65,
+ 0x72, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x0e, 0x0a, 0x0c, 0x50, 0x61, 0x72,
+ 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xa3, 0x02, 0x0a, 0x0d, 0x50, 0x61,
+ 0x72, 0x73, 0x65, 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, 0x4c, 0x0a, 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61,
+ 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x02, 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,
+ 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52,
+ 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x12, 0x54, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73,
+ 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
+ 0x2d, 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, 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, 0x22,
+ 0xb5, 0x02, 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, 0x29, 0x2e,
+ 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, 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, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x06, 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, 0x07, 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, 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,
- 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, 0xbe, 0x02, 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, 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, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73,
- 0x18, 0x06, 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, 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, 0x8c, 0x02, 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, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x03, 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, 0x04, 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, 0x34, 0x0a, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x05, 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, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70,
- 0x65, 0x22, 0xd1, 0x01, 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, 0x70, 0x6c, 0x61, 0x6e,
- 0x18, 0x03, 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, 0x04, 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, 0x42, 0x06, 0x0a,
- 0x04, 0x74, 0x79, 0x70, 0x65, 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,
+ 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72,
+ 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x22, 0x99, 0x03, 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, 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, 0x3a, 0x0a, 0x0a, 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, 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, 0x04, 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, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x06, 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, 0x07, 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, 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, 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, 0xbe, 0x02, 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, 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, 0x74, 0x69, 0x6d, 0x69,
+ 0x6e, 0x67, 0x73, 0x18, 0x06, 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, 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, 0x8c, 0x02, 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, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x03, 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, 0x04, 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, 0x34, 0x0a, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c,
+ 0x18, 0x05, 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, 0x42, 0x06, 0x0a, 0x04,
+ 0x74, 0x79, 0x70, 0x65, 0x22, 0xd1, 0x01, 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, 0x70,
+ 0x6c, 0x61, 0x6e, 0x18, 0x03, 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, 0x04, 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,
+ 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 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, 0x2b, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x43, 0x4f, 0x52,
+ 0x53, 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x49, 0x4d,
+ 0x50, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x41, 0x53, 0x53, 0x54, 0x48, 0x52,
+ 0x55, 0x10, 0x01, 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,
@@ -4060,116 +4121,118 @@ func file_provisionersdk_proto_provisioner_proto_rawDescGZIP() []byte {
return file_provisionersdk_proto_provisioner_proto_rawDescData
}
-var file_provisionersdk_proto_provisioner_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
+var file_provisionersdk_proto_provisioner_proto_enumTypes = make([]protoimpl.EnumInfo, 6)
var file_provisionersdk_proto_provisioner_proto_msgTypes = make([]protoimpl.MessageInfo, 42)
var file_provisionersdk_proto_provisioner_proto_goTypes = []interface{}{
(LogLevel)(0), // 0: provisioner.LogLevel
(AppSharingLevel)(0), // 1: provisioner.AppSharingLevel
- (AppOpenIn)(0), // 2: provisioner.AppOpenIn
- (WorkspaceTransition)(0), // 3: provisioner.WorkspaceTransition
- (TimingState)(0), // 4: provisioner.TimingState
- (*Empty)(nil), // 5: provisioner.Empty
- (*TemplateVariable)(nil), // 6: provisioner.TemplateVariable
- (*RichParameterOption)(nil), // 7: provisioner.RichParameterOption
- (*RichParameter)(nil), // 8: provisioner.RichParameter
- (*RichParameterValue)(nil), // 9: provisioner.RichParameterValue
- (*Prebuild)(nil), // 10: provisioner.Prebuild
- (*Preset)(nil), // 11: provisioner.Preset
- (*PresetParameter)(nil), // 12: provisioner.PresetParameter
- (*VariableValue)(nil), // 13: provisioner.VariableValue
- (*Log)(nil), // 14: provisioner.Log
- (*InstanceIdentityAuth)(nil), // 15: provisioner.InstanceIdentityAuth
- (*ExternalAuthProviderResource)(nil), // 16: provisioner.ExternalAuthProviderResource
- (*ExternalAuthProvider)(nil), // 17: provisioner.ExternalAuthProvider
- (*Agent)(nil), // 18: provisioner.Agent
- (*ResourcesMonitoring)(nil), // 19: provisioner.ResourcesMonitoring
- (*MemoryResourceMonitor)(nil), // 20: provisioner.MemoryResourceMonitor
- (*VolumeResourceMonitor)(nil), // 21: provisioner.VolumeResourceMonitor
- (*DisplayApps)(nil), // 22: provisioner.DisplayApps
- (*Env)(nil), // 23: provisioner.Env
- (*Script)(nil), // 24: provisioner.Script
- (*Devcontainer)(nil), // 25: provisioner.Devcontainer
- (*App)(nil), // 26: provisioner.App
- (*Healthcheck)(nil), // 27: provisioner.Healthcheck
- (*Resource)(nil), // 28: provisioner.Resource
- (*Module)(nil), // 29: provisioner.Module
- (*Role)(nil), // 30: provisioner.Role
- (*Metadata)(nil), // 31: provisioner.Metadata
- (*Config)(nil), // 32: provisioner.Config
- (*ParseRequest)(nil), // 33: provisioner.ParseRequest
- (*ParseComplete)(nil), // 34: provisioner.ParseComplete
- (*PlanRequest)(nil), // 35: provisioner.PlanRequest
- (*PlanComplete)(nil), // 36: provisioner.PlanComplete
- (*ApplyRequest)(nil), // 37: provisioner.ApplyRequest
- (*ApplyComplete)(nil), // 38: provisioner.ApplyComplete
- (*Timing)(nil), // 39: provisioner.Timing
- (*CancelRequest)(nil), // 40: provisioner.CancelRequest
- (*Request)(nil), // 41: provisioner.Request
- (*Response)(nil), // 42: provisioner.Response
- (*Agent_Metadata)(nil), // 43: provisioner.Agent.Metadata
- nil, // 44: provisioner.Agent.EnvEntry
- (*Resource_Metadata)(nil), // 45: provisioner.Resource.Metadata
- nil, // 46: provisioner.ParseComplete.WorkspaceTagsEntry
- (*timestamppb.Timestamp)(nil), // 47: google.protobuf.Timestamp
+ (AppCORSBehavior)(0), // 2: provisioner.AppCORSBehavior
+ (AppOpenIn)(0), // 3: provisioner.AppOpenIn
+ (WorkspaceTransition)(0), // 4: provisioner.WorkspaceTransition
+ (TimingState)(0), // 5: provisioner.TimingState
+ (*Empty)(nil), // 6: provisioner.Empty
+ (*TemplateVariable)(nil), // 7: provisioner.TemplateVariable
+ (*RichParameterOption)(nil), // 8: provisioner.RichParameterOption
+ (*RichParameter)(nil), // 9: provisioner.RichParameter
+ (*RichParameterValue)(nil), // 10: provisioner.RichParameterValue
+ (*Prebuild)(nil), // 11: provisioner.Prebuild
+ (*Preset)(nil), // 12: provisioner.Preset
+ (*PresetParameter)(nil), // 13: provisioner.PresetParameter
+ (*VariableValue)(nil), // 14: provisioner.VariableValue
+ (*Log)(nil), // 15: provisioner.Log
+ (*InstanceIdentityAuth)(nil), // 16: provisioner.InstanceIdentityAuth
+ (*ExternalAuthProviderResource)(nil), // 17: provisioner.ExternalAuthProviderResource
+ (*ExternalAuthProvider)(nil), // 18: provisioner.ExternalAuthProvider
+ (*Agent)(nil), // 19: provisioner.Agent
+ (*ResourcesMonitoring)(nil), // 20: provisioner.ResourcesMonitoring
+ (*MemoryResourceMonitor)(nil), // 21: provisioner.MemoryResourceMonitor
+ (*VolumeResourceMonitor)(nil), // 22: provisioner.VolumeResourceMonitor
+ (*DisplayApps)(nil), // 23: provisioner.DisplayApps
+ (*Env)(nil), // 24: provisioner.Env
+ (*Script)(nil), // 25: provisioner.Script
+ (*Devcontainer)(nil), // 26: provisioner.Devcontainer
+ (*App)(nil), // 27: provisioner.App
+ (*Healthcheck)(nil), // 28: provisioner.Healthcheck
+ (*Resource)(nil), // 29: provisioner.Resource
+ (*Module)(nil), // 30: provisioner.Module
+ (*Role)(nil), // 31: provisioner.Role
+ (*Metadata)(nil), // 32: provisioner.Metadata
+ (*Config)(nil), // 33: provisioner.Config
+ (*ParseRequest)(nil), // 34: provisioner.ParseRequest
+ (*ParseComplete)(nil), // 35: provisioner.ParseComplete
+ (*PlanRequest)(nil), // 36: provisioner.PlanRequest
+ (*PlanComplete)(nil), // 37: provisioner.PlanComplete
+ (*ApplyRequest)(nil), // 38: provisioner.ApplyRequest
+ (*ApplyComplete)(nil), // 39: provisioner.ApplyComplete
+ (*Timing)(nil), // 40: provisioner.Timing
+ (*CancelRequest)(nil), // 41: provisioner.CancelRequest
+ (*Request)(nil), // 42: provisioner.Request
+ (*Response)(nil), // 43: provisioner.Response
+ (*Agent_Metadata)(nil), // 44: provisioner.Agent.Metadata
+ nil, // 45: provisioner.Agent.EnvEntry
+ (*Resource_Metadata)(nil), // 46: provisioner.Resource.Metadata
+ nil, // 47: provisioner.ParseComplete.WorkspaceTagsEntry
+ (*timestamppb.Timestamp)(nil), // 48: google.protobuf.Timestamp
}
var file_provisionersdk_proto_provisioner_proto_depIdxs = []int32{
- 7, // 0: provisioner.RichParameter.options:type_name -> provisioner.RichParameterOption
- 12, // 1: provisioner.Preset.parameters:type_name -> provisioner.PresetParameter
- 10, // 2: provisioner.Preset.prebuild:type_name -> provisioner.Prebuild
+ 8, // 0: provisioner.RichParameter.options:type_name -> provisioner.RichParameterOption
+ 13, // 1: provisioner.Preset.parameters:type_name -> provisioner.PresetParameter
+ 11, // 2: provisioner.Preset.prebuild:type_name -> provisioner.Prebuild
0, // 3: provisioner.Log.level:type_name -> provisioner.LogLevel
- 44, // 4: provisioner.Agent.env:type_name -> provisioner.Agent.EnvEntry
- 26, // 5: provisioner.Agent.apps:type_name -> provisioner.App
- 43, // 6: provisioner.Agent.metadata:type_name -> provisioner.Agent.Metadata
- 22, // 7: provisioner.Agent.display_apps:type_name -> provisioner.DisplayApps
- 24, // 8: provisioner.Agent.scripts:type_name -> provisioner.Script
- 23, // 9: provisioner.Agent.extra_envs:type_name -> provisioner.Env
- 19, // 10: provisioner.Agent.resources_monitoring:type_name -> provisioner.ResourcesMonitoring
- 25, // 11: provisioner.Agent.devcontainers:type_name -> provisioner.Devcontainer
- 20, // 12: provisioner.ResourcesMonitoring.memory:type_name -> provisioner.MemoryResourceMonitor
- 21, // 13: provisioner.ResourcesMonitoring.volumes:type_name -> provisioner.VolumeResourceMonitor
- 27, // 14: provisioner.App.healthcheck:type_name -> provisioner.Healthcheck
+ 45, // 4: provisioner.Agent.env:type_name -> provisioner.Agent.EnvEntry
+ 27, // 5: provisioner.Agent.apps:type_name -> provisioner.App
+ 44, // 6: provisioner.Agent.metadata:type_name -> provisioner.Agent.Metadata
+ 23, // 7: provisioner.Agent.display_apps:type_name -> provisioner.DisplayApps
+ 25, // 8: provisioner.Agent.scripts:type_name -> provisioner.Script
+ 24, // 9: provisioner.Agent.extra_envs:type_name -> provisioner.Env
+ 20, // 10: provisioner.Agent.resources_monitoring:type_name -> provisioner.ResourcesMonitoring
+ 26, // 11: provisioner.Agent.devcontainers:type_name -> provisioner.Devcontainer
+ 21, // 12: provisioner.ResourcesMonitoring.memory:type_name -> provisioner.MemoryResourceMonitor
+ 22, // 13: provisioner.ResourcesMonitoring.volumes:type_name -> provisioner.VolumeResourceMonitor
+ 28, // 14: provisioner.App.healthcheck:type_name -> provisioner.Healthcheck
1, // 15: provisioner.App.sharing_level:type_name -> provisioner.AppSharingLevel
- 2, // 16: provisioner.App.open_in:type_name -> provisioner.AppOpenIn
- 18, // 17: provisioner.Resource.agents:type_name -> provisioner.Agent
- 45, // 18: provisioner.Resource.metadata:type_name -> provisioner.Resource.Metadata
- 3, // 19: provisioner.Metadata.workspace_transition:type_name -> provisioner.WorkspaceTransition
- 30, // 20: provisioner.Metadata.workspace_owner_rbac_roles:type_name -> provisioner.Role
- 6, // 21: provisioner.ParseComplete.template_variables:type_name -> provisioner.TemplateVariable
- 46, // 22: provisioner.ParseComplete.workspace_tags:type_name -> provisioner.ParseComplete.WorkspaceTagsEntry
- 31, // 23: provisioner.PlanRequest.metadata:type_name -> provisioner.Metadata
- 9, // 24: provisioner.PlanRequest.rich_parameter_values:type_name -> provisioner.RichParameterValue
- 13, // 25: provisioner.PlanRequest.variable_values:type_name -> provisioner.VariableValue
- 17, // 26: provisioner.PlanRequest.external_auth_providers:type_name -> provisioner.ExternalAuthProvider
- 28, // 27: provisioner.PlanComplete.resources:type_name -> provisioner.Resource
- 8, // 28: provisioner.PlanComplete.parameters:type_name -> provisioner.RichParameter
- 16, // 29: provisioner.PlanComplete.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource
- 39, // 30: provisioner.PlanComplete.timings:type_name -> provisioner.Timing
- 29, // 31: provisioner.PlanComplete.modules:type_name -> provisioner.Module
- 11, // 32: provisioner.PlanComplete.presets:type_name -> provisioner.Preset
- 31, // 33: provisioner.ApplyRequest.metadata:type_name -> provisioner.Metadata
- 28, // 34: provisioner.ApplyComplete.resources:type_name -> provisioner.Resource
- 8, // 35: provisioner.ApplyComplete.parameters:type_name -> provisioner.RichParameter
- 16, // 36: provisioner.ApplyComplete.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource
- 39, // 37: provisioner.ApplyComplete.timings:type_name -> provisioner.Timing
- 47, // 38: provisioner.Timing.start:type_name -> google.protobuf.Timestamp
- 47, // 39: provisioner.Timing.end:type_name -> google.protobuf.Timestamp
- 4, // 40: provisioner.Timing.state:type_name -> provisioner.TimingState
- 32, // 41: provisioner.Request.config:type_name -> provisioner.Config
- 33, // 42: provisioner.Request.parse:type_name -> provisioner.ParseRequest
- 35, // 43: provisioner.Request.plan:type_name -> provisioner.PlanRequest
- 37, // 44: provisioner.Request.apply:type_name -> provisioner.ApplyRequest
- 40, // 45: provisioner.Request.cancel:type_name -> provisioner.CancelRequest
- 14, // 46: provisioner.Response.log:type_name -> provisioner.Log
- 34, // 47: provisioner.Response.parse:type_name -> provisioner.ParseComplete
- 36, // 48: provisioner.Response.plan:type_name -> provisioner.PlanComplete
- 38, // 49: provisioner.Response.apply:type_name -> provisioner.ApplyComplete
- 41, // 50: provisioner.Provisioner.Session:input_type -> provisioner.Request
- 42, // 51: provisioner.Provisioner.Session:output_type -> provisioner.Response
- 51, // [51:52] is the sub-list for method output_type
- 50, // [50:51] is the sub-list for method input_type
- 50, // [50:50] is the sub-list for extension type_name
- 50, // [50:50] is the sub-list for extension extendee
- 0, // [0:50] is the sub-list for field type_name
+ 3, // 16: provisioner.App.open_in:type_name -> provisioner.AppOpenIn
+ 2, // 17: provisioner.App.cors_behavior:type_name -> provisioner.AppCORSBehavior
+ 19, // 18: provisioner.Resource.agents:type_name -> provisioner.Agent
+ 46, // 19: provisioner.Resource.metadata:type_name -> provisioner.Resource.Metadata
+ 4, // 20: provisioner.Metadata.workspace_transition:type_name -> provisioner.WorkspaceTransition
+ 31, // 21: provisioner.Metadata.workspace_owner_rbac_roles:type_name -> provisioner.Role
+ 7, // 22: provisioner.ParseComplete.template_variables:type_name -> provisioner.TemplateVariable
+ 47, // 23: provisioner.ParseComplete.workspace_tags:type_name -> provisioner.ParseComplete.WorkspaceTagsEntry
+ 32, // 24: provisioner.PlanRequest.metadata:type_name -> provisioner.Metadata
+ 10, // 25: provisioner.PlanRequest.rich_parameter_values:type_name -> provisioner.RichParameterValue
+ 14, // 26: provisioner.PlanRequest.variable_values:type_name -> provisioner.VariableValue
+ 18, // 27: provisioner.PlanRequest.external_auth_providers:type_name -> provisioner.ExternalAuthProvider
+ 29, // 28: provisioner.PlanComplete.resources:type_name -> provisioner.Resource
+ 9, // 29: provisioner.PlanComplete.parameters:type_name -> provisioner.RichParameter
+ 17, // 30: provisioner.PlanComplete.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource
+ 40, // 31: provisioner.PlanComplete.timings:type_name -> provisioner.Timing
+ 30, // 32: provisioner.PlanComplete.modules:type_name -> provisioner.Module
+ 12, // 33: provisioner.PlanComplete.presets:type_name -> provisioner.Preset
+ 32, // 34: provisioner.ApplyRequest.metadata:type_name -> provisioner.Metadata
+ 29, // 35: provisioner.ApplyComplete.resources:type_name -> provisioner.Resource
+ 9, // 36: provisioner.ApplyComplete.parameters:type_name -> provisioner.RichParameter
+ 17, // 37: provisioner.ApplyComplete.external_auth_providers:type_name -> provisioner.ExternalAuthProviderResource
+ 40, // 38: provisioner.ApplyComplete.timings:type_name -> provisioner.Timing
+ 48, // 39: provisioner.Timing.start:type_name -> google.protobuf.Timestamp
+ 48, // 40: provisioner.Timing.end:type_name -> google.protobuf.Timestamp
+ 5, // 41: provisioner.Timing.state:type_name -> provisioner.TimingState
+ 33, // 42: provisioner.Request.config:type_name -> provisioner.Config
+ 34, // 43: provisioner.Request.parse:type_name -> provisioner.ParseRequest
+ 36, // 44: provisioner.Request.plan:type_name -> provisioner.PlanRequest
+ 38, // 45: provisioner.Request.apply:type_name -> provisioner.ApplyRequest
+ 41, // 46: provisioner.Request.cancel:type_name -> provisioner.CancelRequest
+ 15, // 47: provisioner.Response.log:type_name -> provisioner.Log
+ 35, // 48: provisioner.Response.parse:type_name -> provisioner.ParseComplete
+ 37, // 49: provisioner.Response.plan:type_name -> provisioner.PlanComplete
+ 39, // 50: provisioner.Response.apply:type_name -> provisioner.ApplyComplete
+ 42, // 51: provisioner.Provisioner.Session:input_type -> provisioner.Request
+ 43, // 52: provisioner.Provisioner.Session:output_type -> provisioner.Response
+ 52, // [52:53] is the sub-list for method output_type
+ 51, // [51:52] is the sub-list for method input_type
+ 51, // [51:51] is the sub-list for extension type_name
+ 51, // [51:51] is the sub-list for extension extendee
+ 0, // [0:51] is the sub-list for field type_name
}
func init() { file_provisionersdk_proto_provisioner_proto_init() }
@@ -4682,7 +4745,7 @@ func file_provisionersdk_proto_provisioner_proto_init() {
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_provisionersdk_proto_provisioner_proto_rawDesc,
- NumEnums: 5,
+ NumEnums: 6,
NumMessages: 42,
NumExtensions: 0,
NumServices: 1,
diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto
index 3e6841fb24450..f19efe1f41526 100644
--- a/provisionersdk/proto/provisioner.proto
+++ b/provisionersdk/proto/provisioner.proto
@@ -171,6 +171,11 @@ message VolumeResourceMonitor {
int32 threshold = 3;
}
+enum AppCORSBehavior {
+ SIMPLE = 0;
+ PASSTHRU = 1;
+}
+
message DisplayApps {
bool vscode = 1;
bool vscode_insiders = 2;
@@ -225,6 +230,7 @@ message App {
int64 order = 10;
bool hidden = 11;
AppOpenIn open_in = 12;
+ AppCORSBehavior cors_behavior = 13;
}
// Healthcheck represents configuration for checking for app readiness.
diff --git a/site/e2e/provisionerGenerated.ts b/site/e2e/provisionerGenerated.ts
index cea6f9cb364af..2aed339e96bcb 100644
--- a/site/e2e/provisionerGenerated.ts
+++ b/site/e2e/provisionerGenerated.ts
@@ -22,6 +22,12 @@ export enum AppSharingLevel {
UNRECOGNIZED = -1,
}
+export enum AppCORSBehavior {
+ SIMPLE = 0,
+ PASSTHRU = 1,
+ UNRECOGNIZED = -1,
+}
+
export enum AppOpenIn {
/** @deprecated */
WINDOW = 0,
@@ -246,6 +252,7 @@ export interface App {
order: number;
hidden: boolean;
openIn: AppOpenIn;
+ corsBehavior: AppCORSBehavior;
}
/** Healthcheck represents configuration for checking for app readiness. */
@@ -871,6 +878,9 @@ export const App = {
if (message.openIn !== 0) {
writer.uint32(96).int32(message.openIn);
}
+ if (message.corsBehavior !== 0) {
+ writer.uint32(104).int32(message.corsBehavior);
+ }
return writer;
},
};
diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts
index 0350bce141563..d6cc05e7d1243 100644
--- a/site/src/api/typesGenerated.ts
+++ b/site/src/api/typesGenerated.ts
@@ -81,6 +81,11 @@ export const AgentSubsystems: AgentSubsystem[] = [
"exectrace",
];
+// From codersdk/cors_behavior.go
+export type AppCORSBehavior = "passthru" | "simple";
+
+export const AppCORSBehaviors: AppCORSBehavior[] = ["passthru", "simple"];
+
// From codersdk/deployment.go
export interface AppHostResponse {
readonly host: string;