mirror of
https://github.com/hatchet-dev/hatchet.git
synced 2026-04-23 02:34:48 -05:00
feat(security): multiple encryption options, API tokens, easier setup (#125)
* (wip) encryption * feat: api tokens * chore: add api token generation command * fix: e2e tests * chore: set timeout for e2e job * fix: e2e tests, remove client-side certs * chore: address PR review comments * fix: token tests * chore: address review comments and fix tests
This commit is contained in:
@@ -102,6 +102,7 @@ jobs:
|
||||
|
||||
e2e:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
DATABASE_URL: postgresql://hatchet:hatchet@127.0.0.1:5431/hatchet
|
||||
|
||||
@@ -153,14 +154,17 @@ jobs:
|
||||
. .env
|
||||
set +a
|
||||
|
||||
go run ./cmd/hatchet-admin seed
|
||||
go run ./cmd/hatchet-admin quickstart
|
||||
|
||||
go run ./cmd/hatchet-engine &
|
||||
go run ./cmd/hatchet-api &
|
||||
go run ./cmd/hatchet-engine --config ./generated/ &
|
||||
go run ./cmd/hatchet-api --config ./generated/ &
|
||||
sleep 30
|
||||
|
||||
- name: Test
|
||||
run: go test -tags e2e ./... -p 1 -v -failfast
|
||||
run: |
|
||||
export HATCHET_CLIENT_TOKEN="$(go run ./cmd/hatchet-admin token create --config ./generated/ --tenant-id 707d0855-80ab-4e1f-a156-f1c4546cbf52)"
|
||||
|
||||
go test -tags e2e ./... -p 1 -v -failfast
|
||||
|
||||
- name: Teardown
|
||||
run: docker compose down
|
||||
|
||||
@@ -85,3 +85,5 @@ tmp
|
||||
|
||||
postgres-data
|
||||
rabbitmq.conf
|
||||
|
||||
*encryption-keys
|
||||
@@ -0,0 +1,7 @@
|
||||
repos:
|
||||
- repo: https://github.com/gitguardian/ggshield
|
||||
rev: v1.23.0
|
||||
hooks:
|
||||
- id: ggshield
|
||||
language_version: python3
|
||||
stages: [commit]
|
||||
+69
-7
@@ -8,7 +8,7 @@
|
||||
- `docker-compose`
|
||||
- [`Taskfile`](https://taskfile.dev/installation/)
|
||||
- The following additional devtools:
|
||||
- `protoc`: `brew install protobuf@25`
|
||||
- `protoc`: `brew install protobuf@25`
|
||||
- `caddy` and `nss`: `brew install caddy nss`
|
||||
|
||||
### Setup
|
||||
@@ -19,7 +19,9 @@
|
||||
|
||||
3. Generate certificates needed for communicating between the Hatchet client and engine: `task generate-certs`
|
||||
|
||||
4. Create environment variables:
|
||||
4. Generate keysets for encryption: `task generate-local-encryption-keys`
|
||||
|
||||
5. Create environment variables:
|
||||
|
||||
```sh
|
||||
alias randstring='f() { openssl rand -base64 69 | tr -d "\n" | tr -d "=+/" | cut -c1-$1 };f'
|
||||
@@ -30,6 +32,10 @@ SERVER_TLS_CERT_FILE=./hack/dev/certs/cluster.pem
|
||||
SERVER_TLS_KEY_FILE=./hack/dev/certs/cluster.key
|
||||
SERVER_TLS_ROOT_CA_FILE=./hack/dev/certs/ca.cert
|
||||
|
||||
SERVER_ENCRYPTION_MASTER_KEYSET_FILE=./hack/dev/encryption-keys/master.key
|
||||
SERVER_ENCRYPTION_JWT_PRIVATE_KEYSET_FILE=./hack/dev/encryption-keys/private_ec256.key
|
||||
SERVER_ENCRYPTION_JWT_PUBLIC_KEYSET_FILE=./hack/dev/encryption-keys/public_ec256.key
|
||||
|
||||
SERVER_PORT=8080
|
||||
SERVER_URL=https://app.dev.hatchet-tools.com
|
||||
|
||||
@@ -37,22 +43,44 @@ SERVER_AUTH_COOKIE_SECRETS="$(randstring 16) $(randstring 16)"
|
||||
SERVER_AUTH_COOKIE_DOMAIN=app.dev.hatchet-tools.com
|
||||
SERVER_AUTH_COOKIE_INSECURE=false
|
||||
SERVER_AUTH_SET_EMAIL_VERIFIED=true
|
||||
|
||||
SERVER_LOGGER_LEVEL=debug
|
||||
SERVER_LOGGER_FORMAT=console
|
||||
DATABASE_LOGGER_LEVEL=debug
|
||||
DATABASE_LOGGER_FORMAT=console
|
||||
EOF
|
||||
```
|
||||
|
||||
5. Migrate the database: `task prisma-migrate`
|
||||
6. Migrate the database: `task prisma-migrate`
|
||||
|
||||
6. Generate all files: `task generate`
|
||||
7. Generate all files: `task generate`
|
||||
|
||||
7. Seed the database: `task seed-dev`
|
||||
8. Seed the database: `task seed-dev`
|
||||
|
||||
8. Start the Hatchet engine, API server, dashboard, and Prisma studio:
|
||||
9. Start the Hatchet engine, API server, dashboard, and Prisma studio:
|
||||
|
||||
```sh
|
||||
task start-dev
|
||||
```
|
||||
|
||||
10. To create and test workflows, run the examples in the `./examples` directory. You will need to add the tenant (output from the `task seed-dev` command) to the `.env` file in each example directory.
|
||||
### Creating and testing workflows
|
||||
|
||||
To create and test workflows, run the examples in the `./examples` directory.
|
||||
|
||||
You will need to add the tenant (output from the `task seed-dev` command) to the `.env` file in each example directory. An example `.env` file for the `./examples/simple` directory can be generated via:
|
||||
|
||||
```sh
|
||||
alias get_token='go run ./cmd/hatchet-admin token create --name local --tenant-id 707d0855-80ab-4e1f-a156-f1c4546cbf52'
|
||||
|
||||
cat > ./examples/simple/.env <<EOF
|
||||
HATCHET_CLIENT_TENANT_ID=707d0855-80ab-4e1f-a156-f1c4546cbf52
|
||||
HATCHET_CLIENT_TLS_ROOT_CA_FILE=../../hack/dev/certs/ca.cert
|
||||
HATCHET_CLIENT_TLS_SERVER_NAME=cluster
|
||||
HATCHET_CLIENT_TOKEN="$(get_token)"
|
||||
EOF
|
||||
```
|
||||
|
||||
This example can then be run via `go run main.go` from the `./examples/simple` directory.
|
||||
|
||||
### Logging
|
||||
|
||||
@@ -83,3 +111,37 @@ OTEL_EXPORTER_OTLP_HEADERS=<optional-headers>
|
||||
# optional
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT=<collector-url>
|
||||
```
|
||||
|
||||
### CloudKMS
|
||||
|
||||
CloudKMS can be used to generate master encryption keys:
|
||||
|
||||
```
|
||||
gcloud kms keyrings create "development" --location "global"
|
||||
gcloud kms keys create "development" --location "global" --keyring "development" --purpose "encryption"
|
||||
gcloud kms keys list --location "global" --keyring "development"
|
||||
```
|
||||
|
||||
From the last step, copy the Key URI and set the following environment variable:
|
||||
|
||||
```
|
||||
SERVER_ENCRYPTION_CLOUDKMS_KEY_URI=gcp-kms://projects/<PROJECT>/locations/global/keyRings/development/cryptoKeys/development
|
||||
```
|
||||
|
||||
Generate a service account in GCP which can encrypt/decrypt on CloudKMS, then download a service account JSON file and set it via:
|
||||
|
||||
```
|
||||
SERVER_ENCRYPTION_CLOUDKMS_CREDENTIALS_JSON='{...}'
|
||||
```
|
||||
|
||||
## Issues
|
||||
|
||||
### Query engine leakage
|
||||
|
||||
Sometimes the spawned query engines from Prisma don't get killed when hot reloading. You can run `task kill-query-engines` on OSX to kill the query engines.
|
||||
|
||||
Make sure you call `.Disconnect` on the database config object when writing CLI commands which interact with the database. If you don't, and you try to wrap these CLI commands in a new command, it will never exit, for example:
|
||||
|
||||
```
|
||||
export HATCHET_CLIENT_TOKEN="$(go run ./cmd/hatchet-admin token create --tenant-id <tenant>)"
|
||||
```
|
||||
|
||||
+7
-4
@@ -1,9 +1,6 @@
|
||||
version: "3"
|
||||
|
||||
tasks:
|
||||
write-default-env:
|
||||
cmds:
|
||||
- sh ./hack/dev/write-default-env.sh
|
||||
set-etc-hosts:
|
||||
cmds:
|
||||
- sudo sh ./hack/dev/manage-hosts.sh add 127.0.0.1 app.dev.hatchet-tools.com
|
||||
@@ -46,7 +43,13 @@ tasks:
|
||||
- task: generate-api-client
|
||||
generate-certs:
|
||||
cmds:
|
||||
- sh ./hack/dev/generate-temporal-certs.sh ./hack/dev/certs
|
||||
- sh ./hack/dev/generate-x509-certs.sh ./hack/dev/certs
|
||||
generate-local-encryption-keys:
|
||||
cmds:
|
||||
- sh ./hack/dev/generate-local-encryption-keys.sh ./hack/dev/encryption-keys
|
||||
generate-dev-api-token:
|
||||
cmds:
|
||||
- sh ./hack/dev/generate-dev-api-token.sh
|
||||
generate-api-server:
|
||||
cmds:
|
||||
- sh ./hack/oas/generate-server.sh
|
||||
|
||||
@@ -15,17 +15,14 @@ service Dispatcher {
|
||||
}
|
||||
|
||||
message WorkerRegisterRequest {
|
||||
// the tenant id
|
||||
string tenantId = 1;
|
||||
|
||||
// the name of the worker
|
||||
string workerName = 2;
|
||||
string workerName = 1;
|
||||
|
||||
// a list of actions that this worker can run
|
||||
repeated string actions = 3;
|
||||
repeated string actions = 2;
|
||||
|
||||
// (optional) the services for this worker
|
||||
repeated string services = 4;
|
||||
repeated string services = 3;
|
||||
}
|
||||
|
||||
message WorkerRegisterResponse {
|
||||
@@ -74,19 +71,13 @@ message AssignedAction {
|
||||
}
|
||||
|
||||
message WorkerListenRequest {
|
||||
// the tenant id
|
||||
string tenantId = 1;
|
||||
|
||||
// the id of the worker
|
||||
string workerId = 2;
|
||||
string workerId = 1;
|
||||
}
|
||||
|
||||
message WorkerUnsubscribeRequest {
|
||||
// the tenant id to unsubscribe from
|
||||
string tenantId = 1;
|
||||
|
||||
// the id of the worker
|
||||
string workerId = 2;
|
||||
string workerId = 1;
|
||||
}
|
||||
|
||||
message WorkerUnsubscribeResponse {
|
||||
@@ -105,34 +96,31 @@ enum ActionEventType {
|
||||
}
|
||||
|
||||
message ActionEvent {
|
||||
// the tenant id
|
||||
string tenantId = 1;
|
||||
|
||||
// the id of the worker
|
||||
string workerId = 2;
|
||||
string workerId = 1;
|
||||
|
||||
// the id of the job
|
||||
string jobId = 3;
|
||||
string jobId = 2;
|
||||
|
||||
// the job run id
|
||||
string jobRunId = 4;
|
||||
string jobRunId = 3;
|
||||
|
||||
// the id of the step
|
||||
string stepId = 5;
|
||||
string stepId = 4;
|
||||
|
||||
// the step run id
|
||||
string stepRunId = 6;
|
||||
string stepRunId = 5;
|
||||
|
||||
// the action id
|
||||
string actionId = 7;
|
||||
string actionId = 6;
|
||||
|
||||
google.protobuf.Timestamp eventTimestamp = 8;
|
||||
google.protobuf.Timestamp eventTimestamp = 7;
|
||||
|
||||
// the step event type
|
||||
ActionEventType eventType = 9;
|
||||
ActionEventType eventType = 8;
|
||||
|
||||
// the event payload
|
||||
string eventPayload = 10;
|
||||
string eventPayload = 9;
|
||||
}
|
||||
|
||||
message ActionEventResponse {
|
||||
|
||||
@@ -30,28 +30,22 @@ message Event {
|
||||
}
|
||||
|
||||
message PushEventRequest {
|
||||
// the tenant id
|
||||
string tenantId = 1;
|
||||
|
||||
// the key for the event
|
||||
string key = 2;
|
||||
string key = 1;
|
||||
|
||||
// the payload for the event
|
||||
string payload = 3;
|
||||
string payload = 2;
|
||||
|
||||
// when the event was generated
|
||||
google.protobuf.Timestamp eventTimestamp = 4;
|
||||
google.protobuf.Timestamp eventTimestamp = 3;
|
||||
}
|
||||
|
||||
message ListEventRequest {
|
||||
// (required) the tenant id
|
||||
string tenantId = 1;
|
||||
|
||||
// (optional) the number of events to skip
|
||||
int32 offset = 2;
|
||||
int32 offset = 1;
|
||||
|
||||
// (optional) the key for the event
|
||||
string key = 3;
|
||||
string key = 2;
|
||||
}
|
||||
|
||||
message ListEventResponse {
|
||||
@@ -60,9 +54,6 @@ message ListEventResponse {
|
||||
}
|
||||
|
||||
message ReplayEventRequest {
|
||||
// the tenant id
|
||||
string tenantId = 1;
|
||||
|
||||
// the event id to replay
|
||||
string eventId = 2;
|
||||
string eventId = 1;
|
||||
}
|
||||
@@ -108,3 +108,11 @@ WorkerList:
|
||||
$ref: "./worker.yaml#/WorkerList"
|
||||
Worker:
|
||||
$ref: "./worker.yaml#/Worker"
|
||||
APIToken:
|
||||
$ref: "./api_tokens.yaml#/APIToken"
|
||||
CreateAPITokenRequest:
|
||||
$ref: "./api_tokens.yaml#/CreateAPITokenRequest"
|
||||
CreateAPITokenResponse:
|
||||
$ref: "./api_tokens.yaml#/CreateAPITokenResponse"
|
||||
ListAPITokensResponse:
|
||||
$ref: "./api_tokens.yaml#/ListAPITokensResponse"
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
APIToken:
|
||||
type: object
|
||||
properties:
|
||||
metadata:
|
||||
$ref: "./metadata.yaml#/APIResourceMeta"
|
||||
name:
|
||||
type: string
|
||||
description: The name of the API token.
|
||||
maxLength: 255
|
||||
expiresAt:
|
||||
type: string
|
||||
format: date-time
|
||||
description: When the API token expires.
|
||||
required:
|
||||
- metadata
|
||||
- name
|
||||
- expiresAt
|
||||
|
||||
CreateAPITokenRequest:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: A name for the API token.
|
||||
maxLength: 255
|
||||
required:
|
||||
- name
|
||||
|
||||
CreateAPITokenResponse:
|
||||
type: object
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
description: The API token.
|
||||
required:
|
||||
- token
|
||||
|
||||
ListAPITokensResponse:
|
||||
properties:
|
||||
pagination:
|
||||
$ref: "./metadata.yaml#/PaginationResponse"
|
||||
rows:
|
||||
items:
|
||||
$ref: "#/APIToken"
|
||||
type: array
|
||||
@@ -48,6 +48,10 @@ paths:
|
||||
$ref: "./paths/tenant/tenant.yaml#/invites"
|
||||
/api/v1/tenants/{tenant}/invites/{tenant-invite}:
|
||||
$ref: "./paths/tenant/tenant.yaml#/inviteScoped"
|
||||
/api/v1/tenants/{tenant}/api-tokens:
|
||||
$ref: "./paths/api-tokens/api_tokens.yaml#/withTenant"
|
||||
/api/v1/api-tokens/{api-token}:
|
||||
$ref: "./paths/api-tokens/api_tokens.yaml#/revoke"
|
||||
/api/v1/tenants/{tenant}/events:
|
||||
$ref: "./paths/event/event.yaml#/withTenant"
|
||||
/api/v1/tenants/{tenant}/events/replay:
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
withTenant:
|
||||
post:
|
||||
x-resources: ["tenant"]
|
||||
description: Create an API token for a tenant
|
||||
operationId: api-token:create
|
||||
parameters:
|
||||
- description: The tenant id
|
||||
in: path
|
||||
name: tenant
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
minLength: 36
|
||||
maxLength: 36
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/CreateAPITokenRequest"
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/CreateAPITokenResponse"
|
||||
description: Successfully retrieved the workflows
|
||||
"400":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: A malformed or bad request
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: Forbidden
|
||||
summary: Create API Token
|
||||
tags:
|
||||
- API Token
|
||||
get:
|
||||
x-resources: ["tenant"]
|
||||
description: List API tokens for a tenant
|
||||
operationId: api-token:list
|
||||
parameters:
|
||||
- description: The tenant id
|
||||
in: path
|
||||
name: tenant
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
minLength: 36
|
||||
maxLength: 36
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/ListAPITokensResponse"
|
||||
description: Successfully retrieved the workflows
|
||||
"400":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: A malformed or bad request
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: Forbidden
|
||||
summary: List API Tokens
|
||||
tags:
|
||||
- API Token
|
||||
revoke:
|
||||
post:
|
||||
x-resources: ["tenant", "api-token"]
|
||||
description: Revoke an API token for a tenant
|
||||
operationId: api-token:update:revoke
|
||||
parameters:
|
||||
- description: The API token
|
||||
in: path
|
||||
name: api-token
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
minLength: 36
|
||||
maxLength: 36
|
||||
responses:
|
||||
"204":
|
||||
description: Successfully revoked the token
|
||||
"400":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: A malformed or bad request
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: Forbidden
|
||||
summary: Revoke API Token
|
||||
tags:
|
||||
- API Token
|
||||
@@ -16,8 +16,7 @@ service WorkflowService {
|
||||
}
|
||||
|
||||
message PutWorkflowRequest {
|
||||
string tenant_id = 1;
|
||||
CreateWorkflowVersionOpts opts = 2;
|
||||
CreateWorkflowVersionOpts opts = 1;
|
||||
}
|
||||
|
||||
// CreateWorkflowVersionOpts represents options to create a workflow version.
|
||||
@@ -49,17 +48,14 @@ message CreateWorkflowStepOpts {
|
||||
}
|
||||
|
||||
// ListWorkflowsRequest is the request for ListWorkflows.
|
||||
message ListWorkflowsRequest {
|
||||
string tenant_id = 1;
|
||||
}
|
||||
message ListWorkflowsRequest {}
|
||||
|
||||
message ScheduleWorkflowRequest {
|
||||
string tenant_id = 1;
|
||||
string workflow_id = 2;
|
||||
repeated google.protobuf.Timestamp schedules = 3;
|
||||
string workflow_id = 1;
|
||||
repeated google.protobuf.Timestamp schedules = 2;
|
||||
|
||||
// (optional) the input data for the workflow
|
||||
string input = 4;
|
||||
string input = 3;
|
||||
}
|
||||
|
||||
// ListWorkflowsResponse is the response for ListWorkflows.
|
||||
@@ -69,8 +65,7 @@ message ListWorkflowsResponse {
|
||||
|
||||
// ListWorkflowsForEventRequest is the request for ListWorkflowsForEvent.
|
||||
message ListWorkflowsForEventRequest {
|
||||
string tenant_id = 1;
|
||||
string event_key = 2;
|
||||
string event_key = 1;
|
||||
}
|
||||
|
||||
// Workflow represents the Workflow model.
|
||||
@@ -147,11 +142,9 @@ message Step {
|
||||
}
|
||||
|
||||
message DeleteWorkflowRequest {
|
||||
string tenant_id = 1;
|
||||
string workflow_id = 2;
|
||||
string workflow_id = 1;
|
||||
}
|
||||
|
||||
message GetWorkflowByNameRequest {
|
||||
string tenant_id = 1;
|
||||
string name = 2;
|
||||
string name = 1;
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
package authn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/middleware"
|
||||
"github.com/hatchet-dev/hatchet/internal/config/server"
|
||||
"github.com/hatchet-dev/hatchet/internal/repository/prisma/db"
|
||||
)
|
||||
|
||||
type AuthN struct {
|
||||
@@ -51,14 +54,20 @@ func (a *AuthN) authenticate(c echo.Context, r *middleware.RouteInfo) error {
|
||||
|
||||
if r.Security.CookieAuth() {
|
||||
err = a.handleCookieAuth(c)
|
||||
c.Set("auth_strategy", "cookie")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err != nil && !r.Security.BearerAuth() {
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil && r.Security.BearerAuth() {
|
||||
err = a.handleBearerAuth(c)
|
||||
c.Set("auth_strategy", "bearer")
|
||||
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
@@ -136,5 +145,57 @@ func (a *AuthN) handleCookieAuth(c echo.Context) error {
|
||||
}
|
||||
|
||||
func (a *AuthN) handleBearerAuth(c echo.Context) error {
|
||||
panic("implement me")
|
||||
forbidden := echo.NewHTTPError(http.StatusForbidden, "Please provide valid credentials")
|
||||
|
||||
// a tenant id must exist in the context in order for the bearer auth to succeed, since
|
||||
// these tokens are tenant-scoped
|
||||
queriedTenant, ok := c.Get("tenant").(*db.TenantModel)
|
||||
|
||||
if !ok {
|
||||
a.l.Debug().Msgf("tenant not found in context")
|
||||
|
||||
return forbidden
|
||||
}
|
||||
|
||||
token, err := getBearerTokenFromRequest(c.Request())
|
||||
|
||||
if err != nil {
|
||||
a.l.Debug().Err(err).Msg("error getting bearer token from request")
|
||||
|
||||
return forbidden
|
||||
}
|
||||
|
||||
// Validate the token.
|
||||
tenantId, err := a.config.Auth.JWTManager.ValidateTenantToken(token)
|
||||
|
||||
if err != nil {
|
||||
a.l.Debug().Err(err).Msg("error validating tenant token")
|
||||
|
||||
return forbidden
|
||||
}
|
||||
|
||||
// Verify that the tenant id which exists in the context is the same as the tenant id
|
||||
// in the token.
|
||||
if queriedTenant.ID != tenantId {
|
||||
a.l.Debug().Msgf("tenant id in token does not match tenant id in context")
|
||||
|
||||
return forbidden
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var errInvalidAuthHeader = fmt.Errorf("invalid authorization header in request")
|
||||
|
||||
func getBearerTokenFromRequest(r *http.Request) (string, error) {
|
||||
reqToken := r.Header.Get("Authorization")
|
||||
splitToken := strings.Split(reqToken, "Bearer")
|
||||
|
||||
if len(splitToken) != 2 {
|
||||
return "", errInvalidAuthHeader
|
||||
}
|
||||
|
||||
reqToken = strings.TrimSpace(splitToken[1])
|
||||
|
||||
return reqToken, nil
|
||||
}
|
||||
|
||||
@@ -41,6 +41,21 @@ func (a *AuthZ) authorize(c echo.Context, r *middleware.RouteInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
switch c.Get("auth_strategy").(string) {
|
||||
case "cookie":
|
||||
err = a.handleCookieAuth(c, r)
|
||||
case "bearer":
|
||||
err = a.handleBearerAuth(c, r)
|
||||
default:
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "No authorization strategy was checked")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *AuthZ) handleCookieAuth(c echo.Context, r *middleware.RouteInfo) error {
|
||||
unauthorized := echo.NewHTTPError(http.StatusUnauthorized, "Not authorized to view this resource")
|
||||
|
||||
if err := a.ensureVerifiedEmail(c, r); err != nil {
|
||||
@@ -87,6 +102,23 @@ func (a *AuthZ) authorize(c echo.Context, r *middleware.RouteInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var restrictedWithBearerToken = []string{
|
||||
// bearer tokens cannot read, list, or write other bearer tokens
|
||||
"ApiTokenList",
|
||||
"ApiTokenCreate",
|
||||
"ApiTokenUpdateRevoke",
|
||||
}
|
||||
|
||||
// At the moment, there's no further bearer auth because bearer tokens are admin-scoped
|
||||
// and we check that the bearer token has access to the tenant in the authn step.
|
||||
func (a *AuthZ) handleBearerAuth(c echo.Context, r *middleware.RouteInfo) error {
|
||||
if operationIn(r.OperationID, restrictedWithBearerToken) {
|
||||
return echo.NewHTTPError(http.StatusUnauthorized, "Not authorized to perform this operation")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var permittedWithUnverifiedEmail = []string{
|
||||
"UserGetCurrent",
|
||||
"UserUpdateLogout",
|
||||
@@ -116,6 +148,10 @@ var adminAndOwnerOnly = []string{
|
||||
"TenantInviteUpdate",
|
||||
"TenantInviteDelete",
|
||||
"TenantMemberList",
|
||||
// members cannot create API tokens for a tenant, because they have admin permissions
|
||||
"ApiTokenList",
|
||||
"ApiTokenCreate",
|
||||
"ApiTokenUpdateRevoke",
|
||||
}
|
||||
|
||||
func (a *AuthZ) authorizeTenantOperations(tenant *db.TenantModel, tenantMember *db.TenantMemberModel, r *middleware.RouteInfo) error {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package apitokens
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
|
||||
"github.com/hatchet-dev/hatchet/internal/repository/prisma/db"
|
||||
)
|
||||
|
||||
func (a *APITokenService) ApiTokenCreate(ctx echo.Context, request gen.ApiTokenCreateRequestObject) (gen.ApiTokenCreateResponseObject, error) {
|
||||
tenant := ctx.Get("tenant").(*db.TenantModel)
|
||||
|
||||
// validate the request
|
||||
if apiErrors, err := a.config.Validator.ValidateAPI(request.Body); err != nil {
|
||||
return nil, err
|
||||
} else if apiErrors != nil {
|
||||
return gen.ApiTokenCreate400JSONResponse(*apiErrors), nil
|
||||
}
|
||||
|
||||
token, err := a.config.Auth.JWTManager.GenerateTenantToken(tenant.ID, request.Body.Name)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// This is the only time the token is sent over the API
|
||||
return gen.ApiTokenCreate200JSONResponse{
|
||||
Token: token,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package apitokens
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
|
||||
"github.com/hatchet-dev/hatchet/internal/repository/prisma/db"
|
||||
)
|
||||
|
||||
func (a *APITokenService) ApiTokenList(ctx echo.Context, request gen.ApiTokenListRequestObject) (gen.ApiTokenListResponseObject, error) {
|
||||
tenant := ctx.Get("tenant").(*db.TenantModel)
|
||||
|
||||
tokens, err := a.config.Repository.APIToken().ListAPITokensByTenant(tenant.ID)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows := make([]gen.APIToken, len(tokens))
|
||||
|
||||
for i := range tokens {
|
||||
rows[i] = *transformers.ToAPIToken(&tokens[i])
|
||||
}
|
||||
|
||||
return gen.ApiTokenList200JSONResponse(
|
||||
gen.ListAPITokensResponse{
|
||||
Rows: &rows,
|
||||
},
|
||||
), nil
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package apitokens
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
|
||||
"github.com/hatchet-dev/hatchet/internal/repository/prisma/db"
|
||||
)
|
||||
|
||||
func (a *APITokenService) ApiTokenUpdateRevoke(ctx echo.Context, request gen.ApiTokenUpdateRevokeRequestObject) (gen.ApiTokenUpdateRevokeResponseObject, error) {
|
||||
apiToken := ctx.Get("api-token").(*db.APITokenModel)
|
||||
|
||||
err := a.config.Repository.APIToken().RevokeAPIToken(apiToken.ID)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gen.ApiTokenUpdateRevoke204Response{}, nil
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package apitokens
|
||||
|
||||
import (
|
||||
"github.com/hatchet-dev/hatchet/internal/config/server"
|
||||
)
|
||||
|
||||
type APITokenService struct {
|
||||
config *server.ServerConfig
|
||||
}
|
||||
|
||||
func NewAPITokenService(config *server.ServerConfig) *APITokenService {
|
||||
return &APITokenService{
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
@@ -66,11 +66,24 @@ func (u *UserService) upsertGoogleUserFromToken(config *server.ServerConfig, tok
|
||||
|
||||
expiresAt := tok.Expiry
|
||||
|
||||
// use the encryption service to encrypt the access and refresh token
|
||||
accessTokenEncrypted, err := config.Encryption.Encrypt([]byte(tok.AccessToken), "google_access_token")
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to encrypt access token: %s", err.Error())
|
||||
}
|
||||
|
||||
refreshTokenEncrypted, err := config.Encryption.Encrypt([]byte(tok.RefreshToken), "google_refresh_token")
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to encrypt refresh token: %s", err.Error())
|
||||
}
|
||||
|
||||
oauthOpts := &repository.OAuthOpts{
|
||||
Provider: "google",
|
||||
ProviderUserId: gInfo.Sub,
|
||||
AccessToken: tok.AccessToken,
|
||||
RefreshToken: repository.StringPtr(tok.RefreshToken),
|
||||
AccessToken: accessTokenEncrypted,
|
||||
RefreshToken: &refreshTokenEncrypted,
|
||||
ExpiresAt: &expiresAt,
|
||||
}
|
||||
|
||||
|
||||
@@ -116,11 +116,33 @@ type APIResourceMeta struct {
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// APIToken defines model for APIToken.
|
||||
type APIToken struct {
|
||||
// ExpiresAt When the API token expires.
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
Metadata APIResourceMeta `json:"metadata"`
|
||||
|
||||
// Name The name of the API token.
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// AcceptInviteRequest defines model for AcceptInviteRequest.
|
||||
type AcceptInviteRequest struct {
|
||||
Invite string `json:"invite" validate:"required,uuid"`
|
||||
}
|
||||
|
||||
// CreateAPITokenRequest defines model for CreateAPITokenRequest.
|
||||
type CreateAPITokenRequest struct {
|
||||
// Name A name for the API token.
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// CreateAPITokenResponse defines model for CreateAPITokenResponse.
|
||||
type CreateAPITokenResponse struct {
|
||||
// Token The API token.
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
// CreateTenantInviteRequest defines model for CreateTenantInviteRequest.
|
||||
type CreateTenantInviteRequest struct {
|
||||
// Email The email of the user to invite.
|
||||
@@ -231,6 +253,12 @@ type JobRun struct {
|
||||
// JobRunStatus defines model for JobRunStatus.
|
||||
type JobRunStatus string
|
||||
|
||||
// ListAPITokensResponse defines model for ListAPITokensResponse.
|
||||
type ListAPITokensResponse struct {
|
||||
Pagination *PaginationResponse `json:"pagination,omitempty"`
|
||||
Rows *[]APIToken `json:"rows,omitempty"`
|
||||
}
|
||||
|
||||
// PaginationResponse defines model for PaginationResponse.
|
||||
type PaginationResponse struct {
|
||||
// CurrentPage the current page
|
||||
@@ -600,6 +628,9 @@ type WorkflowVersionGetDefinitionParams struct {
|
||||
// TenantCreateJSONRequestBody defines body for TenantCreate for application/json ContentType.
|
||||
type TenantCreateJSONRequestBody = CreateTenantRequest
|
||||
|
||||
// ApiTokenCreateJSONRequestBody defines body for ApiTokenCreate for application/json ContentType.
|
||||
type ApiTokenCreateJSONRequestBody = CreateAPITokenRequest
|
||||
|
||||
// EventUpdateReplayJSONRequestBody defines body for EventUpdateReplay for application/json ContentType.
|
||||
type EventUpdateReplayJSONRequestBody = ReplayEventRequest
|
||||
|
||||
@@ -623,6 +654,9 @@ type UserCreateJSONRequestBody = UserRegisterRequest
|
||||
|
||||
// ServerInterface represents all server handlers.
|
||||
type ServerInterface interface {
|
||||
// Revoke API Token
|
||||
// (POST /api/v1/api-tokens/{api-token})
|
||||
ApiTokenUpdateRevoke(ctx echo.Context, apiToken openapi_types.UUID) error
|
||||
// Get event data
|
||||
// (GET /api/v1/events/{event}/data)
|
||||
EventDataGet(ctx echo.Context, event openapi_types.UUID) error
|
||||
@@ -632,6 +666,12 @@ type ServerInterface interface {
|
||||
// Create tenant
|
||||
// (POST /api/v1/tenants)
|
||||
TenantCreate(ctx echo.Context) error
|
||||
// List API Tokens
|
||||
// (GET /api/v1/tenants/{tenant}/api-tokens)
|
||||
ApiTokenList(ctx echo.Context, tenant openapi_types.UUID) error
|
||||
// Create API Token
|
||||
// (POST /api/v1/tenants/{tenant}/api-tokens)
|
||||
ApiTokenCreate(ctx echo.Context, tenant openapi_types.UUID) error
|
||||
// List events
|
||||
// (GET /api/v1/tenants/{tenant}/events)
|
||||
EventList(ctx echo.Context, tenant openapi_types.UUID, params EventListParams) error
|
||||
@@ -717,6 +757,26 @@ type ServerInterfaceWrapper struct {
|
||||
Handler ServerInterface
|
||||
}
|
||||
|
||||
// ApiTokenUpdateRevoke converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) ApiTokenUpdateRevoke(ctx echo.Context) error {
|
||||
var err error
|
||||
// ------------- Path parameter "api-token" -------------
|
||||
var apiToken openapi_types.UUID
|
||||
|
||||
err = runtime.BindStyledParameterWithLocation("simple", false, "api-token", runtime.ParamLocationPath, ctx.Param("api-token"), &apiToken)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter api-token: %s", err))
|
||||
}
|
||||
|
||||
ctx.Set(BearerAuthScopes, []string{})
|
||||
|
||||
ctx.Set(CookieAuthScopes, []string{})
|
||||
|
||||
// Invoke the callback with all the unmarshaled arguments
|
||||
err = w.Handler.ApiTokenUpdateRevoke(ctx, apiToken)
|
||||
return err
|
||||
}
|
||||
|
||||
// EventDataGet converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) EventDataGet(ctx echo.Context) error {
|
||||
var err error
|
||||
@@ -759,6 +819,46 @@ func (w *ServerInterfaceWrapper) TenantCreate(ctx echo.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// ApiTokenList converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) ApiTokenList(ctx echo.Context) error {
|
||||
var err error
|
||||
// ------------- Path parameter "tenant" -------------
|
||||
var tenant openapi_types.UUID
|
||||
|
||||
err = runtime.BindStyledParameterWithLocation("simple", false, "tenant", runtime.ParamLocationPath, ctx.Param("tenant"), &tenant)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter tenant: %s", err))
|
||||
}
|
||||
|
||||
ctx.Set(BearerAuthScopes, []string{})
|
||||
|
||||
ctx.Set(CookieAuthScopes, []string{})
|
||||
|
||||
// Invoke the callback with all the unmarshaled arguments
|
||||
err = w.Handler.ApiTokenList(ctx, tenant)
|
||||
return err
|
||||
}
|
||||
|
||||
// ApiTokenCreate converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) ApiTokenCreate(ctx echo.Context) error {
|
||||
var err error
|
||||
// ------------- Path parameter "tenant" -------------
|
||||
var tenant openapi_types.UUID
|
||||
|
||||
err = runtime.BindStyledParameterWithLocation("simple", false, "tenant", runtime.ParamLocationPath, ctx.Param("tenant"), &tenant)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter tenant: %s", err))
|
||||
}
|
||||
|
||||
ctx.Set(BearerAuthScopes, []string{})
|
||||
|
||||
ctx.Set(CookieAuthScopes, []string{})
|
||||
|
||||
// Invoke the callback with all the unmarshaled arguments
|
||||
err = w.Handler.ApiTokenCreate(ctx, tenant)
|
||||
return err
|
||||
}
|
||||
|
||||
// EventList converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) EventList(ctx echo.Context) error {
|
||||
var err error
|
||||
@@ -1336,9 +1436,12 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
||||
Handler: si,
|
||||
}
|
||||
|
||||
router.POST(baseURL+"/api/v1/api-tokens/:api-token", wrapper.ApiTokenUpdateRevoke)
|
||||
router.GET(baseURL+"/api/v1/events/:event/data", wrapper.EventDataGet)
|
||||
router.GET(baseURL+"/api/v1/meta", wrapper.MetadataGet)
|
||||
router.POST(baseURL+"/api/v1/tenants", wrapper.TenantCreate)
|
||||
router.GET(baseURL+"/api/v1/tenants/:tenant/api-tokens", wrapper.ApiTokenList)
|
||||
router.POST(baseURL+"/api/v1/tenants/:tenant/api-tokens", wrapper.ApiTokenCreate)
|
||||
router.GET(baseURL+"/api/v1/tenants/:tenant/events", wrapper.EventList)
|
||||
router.GET(baseURL+"/api/v1/tenants/:tenant/events/keys", wrapper.EventKeyList)
|
||||
router.POST(baseURL+"/api/v1/tenants/:tenant/events/replay", wrapper.EventUpdateReplay)
|
||||
@@ -1368,6 +1471,40 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
||||
|
||||
}
|
||||
|
||||
type ApiTokenUpdateRevokeRequestObject struct {
|
||||
ApiToken openapi_types.UUID `json:"api-token"`
|
||||
}
|
||||
|
||||
type ApiTokenUpdateRevokeResponseObject interface {
|
||||
VisitApiTokenUpdateRevokeResponse(w http.ResponseWriter) error
|
||||
}
|
||||
|
||||
type ApiTokenUpdateRevoke204Response struct {
|
||||
}
|
||||
|
||||
func (response ApiTokenUpdateRevoke204Response) VisitApiTokenUpdateRevokeResponse(w http.ResponseWriter) error {
|
||||
w.WriteHeader(204)
|
||||
return nil
|
||||
}
|
||||
|
||||
type ApiTokenUpdateRevoke400JSONResponse APIErrors
|
||||
|
||||
func (response ApiTokenUpdateRevoke400JSONResponse) VisitApiTokenUpdateRevokeResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(400)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type ApiTokenUpdateRevoke403JSONResponse APIErrors
|
||||
|
||||
func (response ApiTokenUpdateRevoke403JSONResponse) VisitApiTokenUpdateRevokeResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(403)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type EventDataGetRequestObject struct {
|
||||
Event openapi_types.UUID `json:"event"`
|
||||
}
|
||||
@@ -1463,6 +1600,77 @@ func (response TenantCreate403JSONResponse) VisitTenantCreateResponse(w http.Res
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type ApiTokenListRequestObject struct {
|
||||
Tenant openapi_types.UUID `json:"tenant"`
|
||||
}
|
||||
|
||||
type ApiTokenListResponseObject interface {
|
||||
VisitApiTokenListResponse(w http.ResponseWriter) error
|
||||
}
|
||||
|
||||
type ApiTokenList200JSONResponse ListAPITokensResponse
|
||||
|
||||
func (response ApiTokenList200JSONResponse) VisitApiTokenListResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type ApiTokenList400JSONResponse APIErrors
|
||||
|
||||
func (response ApiTokenList400JSONResponse) VisitApiTokenListResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(400)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type ApiTokenList403JSONResponse APIErrors
|
||||
|
||||
func (response ApiTokenList403JSONResponse) VisitApiTokenListResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(403)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type ApiTokenCreateRequestObject struct {
|
||||
Tenant openapi_types.UUID `json:"tenant"`
|
||||
Body *ApiTokenCreateJSONRequestBody
|
||||
}
|
||||
|
||||
type ApiTokenCreateResponseObject interface {
|
||||
VisitApiTokenCreateResponse(w http.ResponseWriter) error
|
||||
}
|
||||
|
||||
type ApiTokenCreate200JSONResponse CreateAPITokenResponse
|
||||
|
||||
func (response ApiTokenCreate200JSONResponse) VisitApiTokenCreateResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type ApiTokenCreate400JSONResponse APIErrors
|
||||
|
||||
func (response ApiTokenCreate400JSONResponse) VisitApiTokenCreateResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(400)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type ApiTokenCreate403JSONResponse APIErrors
|
||||
|
||||
func (response ApiTokenCreate403JSONResponse) VisitApiTokenCreateResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(403)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type EventListRequestObject struct {
|
||||
Tenant openapi_types.UUID `json:"tenant"`
|
||||
Params EventListParams
|
||||
@@ -2386,12 +2594,18 @@ func (response WorkflowVersionGetDefinition404JSONResponse) VisitWorkflowVersion
|
||||
}
|
||||
|
||||
type StrictServerInterface interface {
|
||||
ApiTokenUpdateRevoke(ctx echo.Context, request ApiTokenUpdateRevokeRequestObject) (ApiTokenUpdateRevokeResponseObject, error)
|
||||
|
||||
EventDataGet(ctx echo.Context, request EventDataGetRequestObject) (EventDataGetResponseObject, error)
|
||||
|
||||
MetadataGet(ctx echo.Context, request MetadataGetRequestObject) (MetadataGetResponseObject, error)
|
||||
|
||||
TenantCreate(ctx echo.Context, request TenantCreateRequestObject) (TenantCreateResponseObject, error)
|
||||
|
||||
ApiTokenList(ctx echo.Context, request ApiTokenListRequestObject) (ApiTokenListResponseObject, error)
|
||||
|
||||
ApiTokenCreate(ctx echo.Context, request ApiTokenCreateRequestObject) (ApiTokenCreateResponseObject, error)
|
||||
|
||||
EventList(ctx echo.Context, request EventListRequestObject) (EventListResponseObject, error)
|
||||
|
||||
EventKeyList(ctx echo.Context, request EventKeyListRequestObject) (EventKeyListResponseObject, error)
|
||||
@@ -2456,6 +2670,31 @@ type strictHandler struct {
|
||||
middlewares []StrictMiddlewareFunc
|
||||
}
|
||||
|
||||
// ApiTokenUpdateRevoke operation middleware
|
||||
func (sh *strictHandler) ApiTokenUpdateRevoke(ctx echo.Context, apiToken openapi_types.UUID) error {
|
||||
var request ApiTokenUpdateRevokeRequestObject
|
||||
|
||||
request.ApiToken = apiToken
|
||||
|
||||
handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
|
||||
return sh.ssi.ApiTokenUpdateRevoke(ctx, request.(ApiTokenUpdateRevokeRequestObject))
|
||||
}
|
||||
for _, middleware := range sh.middlewares {
|
||||
handler = middleware(handler, "ApiTokenUpdateRevoke")
|
||||
}
|
||||
|
||||
response, err := handler(ctx, request)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if validResponse, ok := response.(ApiTokenUpdateRevokeResponseObject); ok {
|
||||
return validResponse.VisitApiTokenUpdateRevokeResponse(ctx.Response())
|
||||
} else if response != nil {
|
||||
return fmt.Errorf("Unexpected response type: %T", response)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EventDataGet operation middleware
|
||||
func (sh *strictHandler) EventDataGet(ctx echo.Context, event openapi_types.UUID) error {
|
||||
var request EventDataGetRequestObject
|
||||
@@ -2533,6 +2772,62 @@ func (sh *strictHandler) TenantCreate(ctx echo.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApiTokenList operation middleware
|
||||
func (sh *strictHandler) ApiTokenList(ctx echo.Context, tenant openapi_types.UUID) error {
|
||||
var request ApiTokenListRequestObject
|
||||
|
||||
request.Tenant = tenant
|
||||
|
||||
handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
|
||||
return sh.ssi.ApiTokenList(ctx, request.(ApiTokenListRequestObject))
|
||||
}
|
||||
for _, middleware := range sh.middlewares {
|
||||
handler = middleware(handler, "ApiTokenList")
|
||||
}
|
||||
|
||||
response, err := handler(ctx, request)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if validResponse, ok := response.(ApiTokenListResponseObject); ok {
|
||||
return validResponse.VisitApiTokenListResponse(ctx.Response())
|
||||
} else if response != nil {
|
||||
return fmt.Errorf("Unexpected response type: %T", response)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApiTokenCreate operation middleware
|
||||
func (sh *strictHandler) ApiTokenCreate(ctx echo.Context, tenant openapi_types.UUID) error {
|
||||
var request ApiTokenCreateRequestObject
|
||||
|
||||
request.Tenant = tenant
|
||||
|
||||
var body ApiTokenCreateJSONRequestBody
|
||||
if err := ctx.Bind(&body); err != nil {
|
||||
return err
|
||||
}
|
||||
request.Body = &body
|
||||
|
||||
handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
|
||||
return sh.ssi.ApiTokenCreate(ctx, request.(ApiTokenCreateRequestObject))
|
||||
}
|
||||
for _, middleware := range sh.middlewares {
|
||||
handler = middleware(handler, "ApiTokenCreate")
|
||||
}
|
||||
|
||||
response, err := handler(ctx, request)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if validResponse, ok := response.(ApiTokenCreateResponseObject); ok {
|
||||
return validResponse.VisitApiTokenCreateResponse(ctx.Response())
|
||||
} else if response != nil {
|
||||
return fmt.Errorf("Unexpected response type: %T", response)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EventList operation middleware
|
||||
func (sh *strictHandler) EventList(ctx echo.Context, tenant openapi_types.UUID, params EventListParams) error {
|
||||
var request EventListRequestObject
|
||||
@@ -3215,80 +3510,84 @@ func (sh *strictHandler) WorkflowVersionGetDefinition(ctx echo.Context, workflow
|
||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||
var swaggerSpec = []string{
|
||||
|
||||
"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",
|
||||
"L3KShMdhOL+f/38AAAD//1fM3PiCpwAA",
|
||||
}
|
||||
|
||||
// GetSwagger returns the content of the embedded swagger specification file
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package transformers
|
||||
|
||||
import (
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
|
||||
"github.com/hatchet-dev/hatchet/internal/repository/prisma/db"
|
||||
)
|
||||
|
||||
func ToAPIToken(token *db.APITokenModel) *gen.APIToken {
|
||||
res := &gen.APIToken{
|
||||
Metadata: *toAPIMetadata(token.ID, token.CreatedAt, token.UpdatedAt),
|
||||
}
|
||||
|
||||
if expiresAt, ok := token.ExpiresAt(); ok {
|
||||
res.ExpiresAt = expiresAt
|
||||
}
|
||||
|
||||
if name, ok := token.Name(); ok {
|
||||
res.Name = name
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
@@ -20,7 +20,7 @@ func ToWorker(worker *db.WorkerModel) *gen.Worker {
|
||||
apiActions := make([]string, len(actions))
|
||||
|
||||
for i, action := range actions {
|
||||
apiActions[i] = action.ID
|
||||
apiActions[i] = action.ActionID
|
||||
}
|
||||
|
||||
res.Actions = &apiActions
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/authn"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/authz"
|
||||
apitokens "github.com/hatchet-dev/hatchet/api/v1/server/handlers/api-tokens"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/handlers/events"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/handlers/metadata"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/handlers/tenants"
|
||||
@@ -29,6 +30,7 @@ type apiService struct {
|
||||
*workflows.WorkflowService
|
||||
*workers.WorkerService
|
||||
*metadata.MetadataService
|
||||
*apitokens.APITokenService
|
||||
}
|
||||
|
||||
func newAPIService(config *server.ServerConfig) *apiService {
|
||||
@@ -39,6 +41,7 @@ func newAPIService(config *server.ServerConfig) *apiService {
|
||||
WorkflowService: workflows.NewWorkflowService(config),
|
||||
WorkerService: workers.NewWorkerService(config),
|
||||
MetadataService: metadata.NewMetadataService(config),
|
||||
APITokenService: apitokens.NewAPITokenService(config),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +78,25 @@ func (t *APIServer) Run(ctx context.Context) error {
|
||||
return tenant, "", nil
|
||||
})
|
||||
|
||||
populatorMW.RegisterGetter("api-token", func(config *server.ServerConfig, parentId, id string) (result interface{}, uniqueParentId string, err error) {
|
||||
apiToken, err := config.Repository.APIToken().GetAPITokenById(id)
|
||||
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// at the moment, API tokens should have a tenant id, because there are no other types of
|
||||
// API tokens. If we add other types of API tokens, we'll need to pass in a parent id to query
|
||||
// for.
|
||||
tenantId, ok := apiToken.TenantID()
|
||||
|
||||
if !ok {
|
||||
return nil, "", fmt.Errorf("api token has no tenant id")
|
||||
}
|
||||
|
||||
return apiToken, tenantId, nil
|
||||
})
|
||||
|
||||
populatorMW.RegisterGetter("tenant-invite", func(config *server.ServerConfig, parentId, id string) (result interface{}, uniqueParentId string, err error) {
|
||||
tenantInvite, err := config.Repository.TenantInvite().GetTenantInvite(id)
|
||||
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/internal/encryption"
|
||||
)
|
||||
|
||||
var (
|
||||
encryptionKeyDir string
|
||||
cloudKMSCredentialsPath string
|
||||
cloudKMSKeyURI string
|
||||
)
|
||||
|
||||
var keysetCmd = &cobra.Command{
|
||||
Use: "keyset",
|
||||
Short: "command for managing keysets.",
|
||||
}
|
||||
|
||||
var keysetCreateLocalKeysetsCmd = &cobra.Command{
|
||||
Use: "create-local-keys",
|
||||
Short: "create a new local master keyset and JWT public/private keyset.",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := runCreateLocalKeysets()
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Fatal: could not run [keyset create-local-keys] command: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var keysetCreateCloudKMSJWTCmd = &cobra.Command{
|
||||
Use: "create-cloudkms-jwt",
|
||||
Short: "create a new JWT keyset encrypted by a remote CloudKMS repository.",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := runCreateCloudKMSJWTKeyset()
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Fatal: could not run [keyset create-cloudkms-jwt] command: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(keysetCmd)
|
||||
keysetCmd.AddCommand(keysetCreateLocalKeysetsCmd)
|
||||
keysetCmd.AddCommand(keysetCreateCloudKMSJWTCmd)
|
||||
|
||||
keysetCmd.PersistentFlags().StringVar(
|
||||
&encryptionKeyDir,
|
||||
"key-dir",
|
||||
"",
|
||||
"if storing keys on disk, path to the directory where encryption keys should be stored",
|
||||
)
|
||||
|
||||
keysetCreateCloudKMSJWTCmd.PersistentFlags().StringVar(
|
||||
&cloudKMSCredentialsPath,
|
||||
"credentials",
|
||||
"",
|
||||
"path to the JSON credentials file for the CloudKMS repository",
|
||||
)
|
||||
|
||||
keysetCreateCloudKMSJWTCmd.PersistentFlags().StringVar(
|
||||
&cloudKMSKeyURI,
|
||||
"key-uri",
|
||||
"",
|
||||
"URI of the key in the CloudKMS repository",
|
||||
)
|
||||
}
|
||||
|
||||
func runCreateLocalKeysets() error {
|
||||
masterKeyBytes, privateEc256, publicEc256, err := encryption.GenerateLocalKeys()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if encryptionKeyDir != "" {
|
||||
// we write these as .key files so that they're gitignored by default
|
||||
err = os.WriteFile(encryptionKeyDir+"/master.key", masterKeyBytes, 0600)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.WriteFile(encryptionKeyDir+"/private_ec256.key", privateEc256, 0600)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.WriteFile(encryptionKeyDir+"/public_ec256.key", publicEc256, 0600)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Master Key Bytes:")
|
||||
fmt.Println(string(masterKeyBytes))
|
||||
|
||||
fmt.Println("Private EC256 Keyset:")
|
||||
fmt.Println(string(privateEc256))
|
||||
|
||||
fmt.Println("Public EC256 Keyset:")
|
||||
fmt.Println(string(publicEc256))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runCreateCloudKMSJWTKeyset() error {
|
||||
if cloudKMSCredentialsPath == "" {
|
||||
return fmt.Errorf("missing required flag --credentials")
|
||||
}
|
||||
|
||||
if cloudKMSKeyURI == "" {
|
||||
return fmt.Errorf("missing required flag --key-uri")
|
||||
}
|
||||
|
||||
credentials, err := os.ReadFile(cloudKMSCredentialsPath)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
privateEc256, publicEc256, err := encryption.GenerateJWTKeysetsFromCloudKMS(cloudKMSKeyURI, credentials)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Private EC256 Keyset:")
|
||||
fmt.Println(string(privateEc256))
|
||||
|
||||
fmt.Println("Public EC256 Keyset:")
|
||||
fmt.Println(string(publicEc256))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -229,6 +229,39 @@ func generateKeys(generated *generatedConfigFiles) error {
|
||||
generated.sc.Auth.Cookie.Secrets = fmt.Sprintf("%s %s", cookieHashKey, cookieBlockKey)
|
||||
}
|
||||
|
||||
// if using local keys, generate master key
|
||||
if !generated.sc.Encryption.CloudKMS.Enabled {
|
||||
masterKeyBytes, privateEc256, publicEc256, err := encryption.GenerateLocalKeys()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if overwrite || (generated.sc.Encryption.MasterKeyset == "") {
|
||||
generated.sc.Encryption.MasterKeyset = string(masterKeyBytes)
|
||||
}
|
||||
|
||||
if overwrite || (generated.sc.Encryption.JWT.PublicJWTKeyset == "") || (generated.sc.Encryption.JWT.PrivateJWTKeyset == "") {
|
||||
generated.sc.Encryption.JWT.PrivateJWTKeyset = string(privateEc256)
|
||||
generated.sc.Encryption.JWT.PublicJWTKeyset = string(publicEc256)
|
||||
}
|
||||
}
|
||||
|
||||
// generate jwt keys
|
||||
if generated.sc.Encryption.CloudKMS.Enabled && (overwrite || (generated.sc.Encryption.JWT.PublicJWTKeyset == "") || (generated.sc.Encryption.JWT.PrivateJWTKeyset == "")) {
|
||||
privateEc256, publicEc256, err := encryption.GenerateJWTKeysetsFromCloudKMS(
|
||||
generated.sc.Encryption.CloudKMS.KeyURI,
|
||||
[]byte(generated.sc.Encryption.CloudKMS.CredentialsJSON),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
generated.sc.Encryption.JWT.PrivateJWTKeyset = string(privateEc256)
|
||||
generated.sc.Encryption.JWT.PublicJWTKeyset = string(publicEc256)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,8 @@ func runSeed(cf *loader.ConfigLoader) error {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer dc.Disconnect() // nolint: errcheck
|
||||
|
||||
shouldSeedUser := dc.Seed.AdminEmail != "" && dc.Seed.AdminPassword != ""
|
||||
var userId string
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/internal/config/loader"
|
||||
)
|
||||
|
||||
var (
|
||||
tokenTenantId string
|
||||
tokenName string
|
||||
)
|
||||
|
||||
var tokenCmd = &cobra.Command{
|
||||
Use: "token",
|
||||
Short: "command for generating tokens.",
|
||||
}
|
||||
|
||||
var tokenCreateAPICmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "create a new API token.",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := runCreateAPIToken()
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Fatal: could not run [token create] command: %v\n", err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(tokenCmd)
|
||||
tokenCmd.AddCommand(tokenCreateAPICmd)
|
||||
|
||||
tokenCreateAPICmd.PersistentFlags().StringVar(
|
||||
&tokenTenantId,
|
||||
"tenant-id",
|
||||
"",
|
||||
"the tenant ID to associate with the token",
|
||||
)
|
||||
|
||||
// require the tenant ID
|
||||
tokenCreateAPICmd.MarkPersistentFlagRequired("tenant-id") // nolint: errcheck
|
||||
|
||||
tokenCreateAPICmd.PersistentFlags().StringVar(
|
||||
&tokenName,
|
||||
"name",
|
||||
"default",
|
||||
"the name of the token",
|
||||
)
|
||||
}
|
||||
|
||||
func runCreateAPIToken() error {
|
||||
// read in the local config
|
||||
configLoader := loader.NewConfigLoader(configDirectory)
|
||||
|
||||
serverConf, err := configLoader.LoadServerConfig()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer serverConf.Disconnect() // nolint: errcheck
|
||||
|
||||
defaultTok, err := serverConf.Auth.JWTManager.GenerateTenantToken(tokenTenantId, tokenName)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(defaultTok)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -134,6 +134,7 @@ func startEngineOrDie(cf *loader.ConfigLoader, interruptCh <-chan interface{}) {
|
||||
}
|
||||
|
||||
grpcOpts := []grpc.ServerOpt{
|
||||
grpc.WithConfig(sc),
|
||||
grpc.WithIngestor(ei),
|
||||
grpc.WithDispatcher(d),
|
||||
grpc.WithAdmin(adminSvc),
|
||||
|
||||
@@ -6,10 +6,11 @@ import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/pkg/client"
|
||||
"github.com/hatchet-dev/hatchet/pkg/cmdutils"
|
||||
"github.com/hatchet-dev/hatchet/pkg/worker"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
type userCreateEvent struct {
|
||||
@@ -141,4 +142,6 @@ func run(ch <-chan interface{}, events chan<- string) error {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import yaml from 'react-syntax-highlighter/dist/esm/languages/hljs/yaml';
|
||||
import json from 'react-syntax-highlighter/dist/esm/languages/hljs/json';
|
||||
|
||||
import { anOldHope } from 'react-syntax-highlighter/dist/esm/styles/hljs';
|
||||
import CopyToClipboard from './copy-to-clipboard';
|
||||
|
||||
SyntaxHighlighter.registerLanguage('typescript', typescript);
|
||||
SyntaxHighlighter.registerLanguage('yaml', yaml);
|
||||
@@ -16,18 +17,24 @@ export function Code({
|
||||
language,
|
||||
className,
|
||||
maxHeight,
|
||||
maxWidth,
|
||||
copy,
|
||||
wrapLines = true,
|
||||
}: {
|
||||
children: string;
|
||||
language: string;
|
||||
className?: string;
|
||||
maxHeight?: string;
|
||||
maxWidth?: string;
|
||||
copy?: boolean;
|
||||
wrapLines?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div className={cn('text-xs', className)}>
|
||||
<div className={cn('text-xs flex flex-col gap-4 justify-end', className)}>
|
||||
<SyntaxHighlighter
|
||||
language={language}
|
||||
style={anOldHope}
|
||||
wrapLines={true}
|
||||
wrapLines={wrapLines}
|
||||
lineProps={{
|
||||
style: { wordBreak: 'break-all', whiteSpace: 'pre-wrap' },
|
||||
}}
|
||||
@@ -35,46 +42,14 @@ export function Code({
|
||||
background: 'hsl(var(--muted) / 0.5)',
|
||||
borderRadius: '0.5rem',
|
||||
maxHeight: maxHeight,
|
||||
maxWidth: maxWidth,
|
||||
fontFamily:
|
||||
"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
|
||||
}}
|
||||
>
|
||||
{children.trim()}
|
||||
</SyntaxHighlighter>
|
||||
{copy && <CopyToClipboard text={children.trim()} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// import { Fragment } from "react";
|
||||
// import { Highlight, themes } from "prism-react-renderer";
|
||||
|
||||
// const theme = themes.nightOwl;
|
||||
|
||||
// export function Code({
|
||||
// children,
|
||||
// language,
|
||||
// }: {
|
||||
// children: string;
|
||||
// language: string;
|
||||
// }) {
|
||||
// return (
|
||||
// <Highlight code={children.trimEnd()} language={language} theme={theme}>
|
||||
// {({ className, style, tokens, getTokenProps }) => (
|
||||
// <pre className={className} style={style}>
|
||||
// <code>
|
||||
// {tokens.map((line, lineIndex) => (
|
||||
// <Fragment key={lineIndex}>
|
||||
// {line
|
||||
// .filter((token) => !token.empty)
|
||||
// .map((token, tokenIndex) => (
|
||||
// <span key={tokenIndex} {...getTokenProps({ token })} />
|
||||
// ))}
|
||||
// {"\n"}
|
||||
// </Fragment>
|
||||
// ))}
|
||||
// </code>
|
||||
// </pre>
|
||||
// )}
|
||||
// </Highlight>
|
||||
// );
|
||||
// }
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Button } from './button';
|
||||
import { CopyIcon } from '@radix-ui/react-icons';
|
||||
import { CheckCircleIcon } from '@heroicons/react/24/outline';
|
||||
|
||||
type Props = {
|
||||
text: string;
|
||||
};
|
||||
|
||||
const CopyToClipboard: React.FC<Props> = ({ text }) => {
|
||||
const [successCopy, setSuccessCopy] = useState(false);
|
||||
|
||||
return (
|
||||
<Button
|
||||
className="max-w-fit"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(text);
|
||||
setSuccessCopy(true);
|
||||
|
||||
setTimeout(() => {
|
||||
setSuccessCopy(false);
|
||||
}, 2000);
|
||||
}}
|
||||
>
|
||||
{successCopy ? (
|
||||
<CheckCircleIcon className="w-4 h-4 mr-2" />
|
||||
) : (
|
||||
<CopyIcon className="w-4 h-4 mr-2" />
|
||||
)}
|
||||
{successCopy ? 'Copied!' : 'Copy to clipboard'}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default CopyToClipboard;
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
APIErrors,
|
||||
APIMeta,
|
||||
AcceptInviteRequest,
|
||||
CreateAPITokenRequest,
|
||||
CreateAPITokenResponse,
|
||||
CreateTenantInviteRequest,
|
||||
CreateTenantRequest,
|
||||
EventData,
|
||||
@@ -23,6 +25,7 @@ import {
|
||||
EventOrderByDirection,
|
||||
EventOrderByField,
|
||||
EventSearch,
|
||||
ListAPITokensResponse,
|
||||
RejectInviteRequest,
|
||||
ReplayEventRequest,
|
||||
Tenant,
|
||||
@@ -322,6 +325,58 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
|
||||
format: "json",
|
||||
...params,
|
||||
});
|
||||
/**
|
||||
* @description Create an API token for a tenant
|
||||
*
|
||||
* @tags API Token
|
||||
* @name ApiTokenCreate
|
||||
* @summary Create API Token
|
||||
* @request POST:/api/v1/tenants/{tenant}/api-tokens
|
||||
* @secure
|
||||
*/
|
||||
apiTokenCreate = (tenant: string, data: CreateAPITokenRequest, params: RequestParams = {}) =>
|
||||
this.request<CreateAPITokenResponse, APIErrors>({
|
||||
path: `/api/v1/tenants/${tenant}/api-tokens`,
|
||||
method: "POST",
|
||||
body: data,
|
||||
secure: true,
|
||||
type: ContentType.Json,
|
||||
format: "json",
|
||||
...params,
|
||||
});
|
||||
/**
|
||||
* @description List API tokens for a tenant
|
||||
*
|
||||
* @tags API Token
|
||||
* @name ApiTokenList
|
||||
* @summary List API Tokens
|
||||
* @request GET:/api/v1/tenants/{tenant}/api-tokens
|
||||
* @secure
|
||||
*/
|
||||
apiTokenList = (tenant: string, params: RequestParams = {}) =>
|
||||
this.request<ListAPITokensResponse, APIErrors>({
|
||||
path: `/api/v1/tenants/${tenant}/api-tokens`,
|
||||
method: "GET",
|
||||
secure: true,
|
||||
format: "json",
|
||||
...params,
|
||||
});
|
||||
/**
|
||||
* @description Revoke an API token for a tenant
|
||||
*
|
||||
* @tags API Token
|
||||
* @name ApiTokenUpdateRevoke
|
||||
* @summary Revoke API Token
|
||||
* @request POST:/api/v1/api-tokens/{api-token}
|
||||
* @secure
|
||||
*/
|
||||
apiTokenUpdateRevoke = (apiToken: string, params: RequestParams = {}) =>
|
||||
this.request<void, APIErrors>({
|
||||
path: `/api/v1/api-tokens/${apiToken}`,
|
||||
method: "POST",
|
||||
secure: true,
|
||||
...params,
|
||||
});
|
||||
/**
|
||||
* @description Lists all events for a tenant.
|
||||
*
|
||||
|
||||
@@ -533,3 +533,35 @@ export interface Worker {
|
||||
/** The recent step runs for this worker. */
|
||||
recentStepRuns?: StepRun[];
|
||||
}
|
||||
|
||||
export interface APIToken {
|
||||
metadata: APIResourceMeta;
|
||||
/**
|
||||
* The name of the API token.
|
||||
* @maxLength 255
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* When the API token expires.
|
||||
* @format date-time
|
||||
*/
|
||||
expiresAt: string;
|
||||
}
|
||||
|
||||
export interface CreateAPITokenRequest {
|
||||
/**
|
||||
* A name for the API token.
|
||||
* @maxLength 255
|
||||
*/
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface CreateAPITokenResponse {
|
||||
/** The API token. */
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface ListAPITokensResponse {
|
||||
pagination?: PaginationResponse;
|
||||
rows?: APIToken[];
|
||||
}
|
||||
|
||||
@@ -26,6 +26,12 @@ export const queries = createQueryKeyStore({
|
||||
queryFn: async () => (await api.tenantMemberList(tenant)).data,
|
||||
}),
|
||||
},
|
||||
tokens: {
|
||||
list: (tenant: string) => ({
|
||||
queryKey: ['api-token:list', tenant],
|
||||
queryFn: async () => (await api.apiTokenList(tenant)).data,
|
||||
}),
|
||||
},
|
||||
invites: {
|
||||
list: (tenant: string) => ({
|
||||
queryKey: ['tenant-invite:list', tenant],
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { ColumnDef } from '@tanstack/react-table';
|
||||
import { DataTableColumnHeader } from '../../../../components/molecules/data-table/data-table-column-header';
|
||||
import { APIToken } from '@/lib/api';
|
||||
import { DataTableRowActions } from '@/components/molecules/data-table/data-table-row-actions';
|
||||
import { relativeDate } from '@/lib/utils';
|
||||
|
||||
export const columns = ({
|
||||
onRevokeClick,
|
||||
}: {
|
||||
onRevokeClick: (row: APIToken) => void;
|
||||
}): ColumnDef<APIToken>[] => {
|
||||
return [
|
||||
{
|
||||
accessorKey: 'name',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Name" />
|
||||
),
|
||||
cell: ({ row }) => <div>{row.getValue('name')}</div>,
|
||||
enableSorting: false,
|
||||
enableHiding: false,
|
||||
},
|
||||
{
|
||||
accessorKey: 'created',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Created" />
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<div>{relativeDate(row.original.metadata.createdAt)}</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'Expires',
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title="Expires" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
return <div>{relativeDate(row.original.expiresAt)}</div>;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
cell: ({ row }) => (
|
||||
<DataTableRowActions
|
||||
row={row}
|
||||
actions={[
|
||||
{
|
||||
label: 'Revoke',
|
||||
onClick: () => onRevokeClick(row.original),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
import {
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Code } from '@/components/ui/code';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { z } from 'zod';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Spinner } from '@/components/ui/loading';
|
||||
|
||||
const schema = z.object({
|
||||
name: z.string().min(1).max(255),
|
||||
});
|
||||
|
||||
interface CreateTokenDialogProps {
|
||||
className?: string;
|
||||
token?: string;
|
||||
onSubmit: (opts: z.infer<typeof schema>) => void;
|
||||
isLoading: boolean;
|
||||
fieldErrors?: Record<string, string>;
|
||||
}
|
||||
|
||||
export function CreateTokenDialog({
|
||||
className,
|
||||
token,
|
||||
...props
|
||||
}: CreateTokenDialogProps) {
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm<z.infer<typeof schema>>({
|
||||
resolver: zodResolver(schema),
|
||||
});
|
||||
|
||||
const nameError = errors.name?.message?.toString() || props.fieldErrors?.name;
|
||||
|
||||
if (token) {
|
||||
return (
|
||||
<DialogContent className="w-fit max-w-[700px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Keep it secret, keep it safe</DialogTitle>
|
||||
</DialogHeader>
|
||||
<p className="text-sm">
|
||||
This is the only time we will show you this token. Make sure to copy
|
||||
it somewhere safe.
|
||||
</p>
|
||||
<Code
|
||||
language="typescript"
|
||||
className="text-sm"
|
||||
wrapLines={false}
|
||||
maxWidth={'calc(700px - 4rem)'}
|
||||
copy
|
||||
>
|
||||
{token}
|
||||
</Code>
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: add a name for the token
|
||||
|
||||
return (
|
||||
<DialogContent className="w-fit max-w-[80%] min-w-[500px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Create a new API token</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className={cn('grid gap-6', className)}>
|
||||
<form
|
||||
onSubmit={handleSubmit((d) => {
|
||||
props.onSubmit(d);
|
||||
})}
|
||||
>
|
||||
<div className="grid gap-4">
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="email">Name</Label>
|
||||
<Input
|
||||
{...register('name')}
|
||||
id="api-token-name"
|
||||
placeholder="My Token"
|
||||
autoCapitalize="none"
|
||||
autoCorrect="off"
|
||||
disabled={props.isLoading}
|
||||
/>
|
||||
{nameError && (
|
||||
<div className="text-sm text-red-500">{nameError}</div>
|
||||
)}
|
||||
</div>
|
||||
<Button disabled={props.isLoading}>
|
||||
{props.isLoading && <Spinner />}
|
||||
Generate token
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
@@ -43,7 +43,6 @@ export const columns = ({
|
||||
<DataTableColumnHeader column={column} title="Expires" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
console.log(row.original.expires);
|
||||
return <div>{relativeDate(row.original.expires)}</div>;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Spinner } from '@/components/ui/loading.tsx';
|
||||
import {
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import { APIToken } from '@/lib/api';
|
||||
|
||||
interface RevokeTokenFormProps {
|
||||
className?: string;
|
||||
onSubmit: (apiToken: APIToken) => void;
|
||||
onCancel: () => void;
|
||||
apiToken: APIToken;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
export function RevokeTokenForm({ className, ...props }: RevokeTokenFormProps) {
|
||||
return (
|
||||
<DialogContent className="w-fit max-w-[80%] min-w-[500px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Delete invite</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div>
|
||||
<div className="text-sm text-foreground mb-4">
|
||||
Are you sure you want to revoke the API token {props.apiToken.name}?
|
||||
This action will immediately prevent any services running with this
|
||||
token from dispatching events or executing steps.
|
||||
</div>
|
||||
<div className="flex flex-row gap-4">
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
props.onCancel();
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
onClick={() => {
|
||||
props.onSubmit(props.apiToken);
|
||||
}}
|
||||
>
|
||||
{props.isLoading && <Spinner />}
|
||||
Revoke API token
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import { CreateInviteForm } from './components/create-invite-form';
|
||||
import { useApiError } from '@/lib/hooks';
|
||||
import { useMutation, useQuery } from '@tanstack/react-query';
|
||||
import api, {
|
||||
APIToken,
|
||||
CreateAPITokenRequest,
|
||||
CreateTenantInviteRequest,
|
||||
TenantInvite,
|
||||
UpdateTenantInviteRequest,
|
||||
@@ -16,8 +18,11 @@ import { Dialog } from '@/components/ui/dialog';
|
||||
import { DataTable } from '@/components/molecules/data-table/data-table';
|
||||
import { columns } from './components/invites-columns';
|
||||
import { columns as membersColumns } from './components/members-columns';
|
||||
import { columns as apiTokensColumns } from './components/api-tokens-columns';
|
||||
import { UpdateInviteForm } from './components/update-invite-form';
|
||||
import { DeleteInviteForm } from './components/delete-invite-form';
|
||||
import { CreateTokenDialog } from './components/create-token-dialog';
|
||||
import { RevokeTokenForm } from './components/revoke-token-form';
|
||||
|
||||
export default function TenantSettings() {
|
||||
const { tenant } = useOutletContext<TenantContextType>();
|
||||
@@ -32,6 +37,8 @@ export default function TenantSettings() {
|
||||
<MembersList />
|
||||
<Separator className="my-4" />
|
||||
<InvitesList />
|
||||
<Separator className="my-4" />
|
||||
<TokensList />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -247,3 +254,137 @@ function DeleteInvite({
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
function TokensList() {
|
||||
const { tenant } = useOutletContext<TenantContextType>();
|
||||
const [showTokenDialog, setShowTokenDialog] = useState(false);
|
||||
const [revokeToken, setRevokeToken] = useState<APIToken | null>(null);
|
||||
|
||||
const listTokensQuery = useQuery({
|
||||
...queries.tokens.list(tenant.metadata.id),
|
||||
});
|
||||
|
||||
const cols = apiTokensColumns({
|
||||
onRevokeClick: (row) => {
|
||||
setRevokeToken(row);
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex flex-row justify-between items-center">
|
||||
<h3 className="text-xl font-semibold leading-tight text-foreground">
|
||||
API Tokens
|
||||
</h3>
|
||||
<Button key="create-api-token" onClick={() => setShowTokenDialog(true)}>
|
||||
Create API Token
|
||||
</Button>
|
||||
</div>
|
||||
<Separator className="my-4" />
|
||||
<DataTable
|
||||
isLoading={listTokensQuery.isLoading}
|
||||
columns={cols}
|
||||
data={listTokensQuery.data?.rows || []}
|
||||
filters={[]}
|
||||
getRowId={(row) => row.metadata.id}
|
||||
/>
|
||||
{showTokenDialog && (
|
||||
<CreateToken
|
||||
tenant={tenant.metadata.id}
|
||||
showTokenDialog={showTokenDialog}
|
||||
setShowTokenDialog={setShowTokenDialog}
|
||||
onSuccess={() => {
|
||||
listTokensQuery.refetch();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{revokeToken && (
|
||||
<RevokeToken
|
||||
tenant={tenant.metadata.id}
|
||||
apiToken={revokeToken}
|
||||
setShowTokenRevoke={() => setRevokeToken(null)}
|
||||
onSuccess={() => {
|
||||
setRevokeToken(null);
|
||||
listTokensQuery.refetch();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function CreateToken({
|
||||
tenant,
|
||||
showTokenDialog,
|
||||
setShowTokenDialog,
|
||||
onSuccess,
|
||||
}: {
|
||||
tenant: string;
|
||||
onSuccess: () => void;
|
||||
showTokenDialog: boolean;
|
||||
setShowTokenDialog: (show: boolean) => void;
|
||||
}) {
|
||||
const [generatedToken, setGeneratedToken] = useState<string | undefined>();
|
||||
const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});
|
||||
const { handleApiError } = useApiError({
|
||||
setFieldErrors: setFieldErrors,
|
||||
});
|
||||
|
||||
const createTokenMutation = useMutation({
|
||||
mutationKey: ['api-token:create', tenant],
|
||||
mutationFn: async (data: CreateAPITokenRequest) => {
|
||||
const res = await api.apiTokenCreate(tenant, data);
|
||||
return res.data;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
setGeneratedToken(data.token);
|
||||
onSuccess();
|
||||
},
|
||||
onError: handleApiError,
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog open={showTokenDialog} onOpenChange={setShowTokenDialog}>
|
||||
<CreateTokenDialog
|
||||
isLoading={createTokenMutation.isPending}
|
||||
onSubmit={createTokenMutation.mutate}
|
||||
token={generatedToken}
|
||||
fieldErrors={fieldErrors}
|
||||
/>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
function RevokeToken({
|
||||
tenant,
|
||||
apiToken,
|
||||
setShowTokenRevoke,
|
||||
onSuccess,
|
||||
}: {
|
||||
tenant: string;
|
||||
apiToken: APIToken;
|
||||
setShowTokenRevoke: (show: boolean) => void;
|
||||
onSuccess: () => void;
|
||||
}) {
|
||||
const { handleApiError } = useApiError({});
|
||||
|
||||
const revokeMutation = useMutation({
|
||||
mutationKey: ['api-token:revoke', tenant, apiToken],
|
||||
mutationFn: async () => {
|
||||
await api.apiTokenUpdateRevoke(apiToken.metadata.id);
|
||||
},
|
||||
onSuccess: onSuccess,
|
||||
onError: handleApiError,
|
||||
});
|
||||
|
||||
return (
|
||||
<Dialog open={!!apiToken} onOpenChange={setShowTokenRevoke}>
|
||||
<RevokeTokenForm
|
||||
apiToken={apiToken}
|
||||
isLoading={revokeMutation.isPending}
|
||||
onSubmit={() => revokeMutation.mutate()}
|
||||
onCancel={() => setShowTokenRevoke(false)}
|
||||
/>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -20,17 +20,23 @@ require (
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/viper v1.16.0
|
||||
github.com/steebchen/prisma-client-go v0.32.1
|
||||
github.com/tink-crypto/tink-go v0.0.0-20230613075026-d6de17e3f164
|
||||
github.com/tink-crypto/tink-go-gcpkms v0.0.0-20230602082706-31d0d09ccc8d
|
||||
go.opentelemetry.io/otel v1.21.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0
|
||||
go.opentelemetry.io/otel/sdk v1.21.0
|
||||
go.opentelemetry.io/otel/trace v1.21.0
|
||||
google.golang.org/api v0.157.0
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.23.3 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.3.0 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
@@ -39,6 +45,10 @@ require (
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect
|
||||
@@ -57,12 +67,14 @@ require (
|
||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.21.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -75,6 +87,7 @@ require (
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/uuid v1.5.0
|
||||
github.com/gorilla/schema v1.2.1
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
@@ -96,12 +109,12 @@ require (
|
||||
golang.org/x/crypto v0.18.0
|
||||
golang.org/x/net v0.20.0 // indirect
|
||||
golang.org/x/oauth2 v0.16.0
|
||||
golang.org/x/sync v0.4.0
|
||||
golang.org/x/sync v0.6.0
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
|
||||
google.golang.org/grpc v1.59.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect
|
||||
google.golang.org/grpc v1.60.1
|
||||
google.golang.org/protobuf v1.32.0
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
@@ -23,6 +23,10 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
|
||||
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
@@ -71,6 +75,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
@@ -118,6 +124,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
@@ -140,6 +148,7 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
@@ -152,6 +161,7 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
@@ -174,11 +184,17 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
|
||||
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
@@ -191,6 +207,8 @@ github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8L
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1 h1:HcUWd006luQPljE73d5sk+/VgYPGUReEVz2y1/qylwY=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1/go.mod h1:w9Y7gY31krpLmrVU5ZPG9H7l9fZuRu5/3R3S3FMtVQ4=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
@@ -301,8 +319,6 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
||||
github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc=
|
||||
github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg=
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||
github.com/steebchen/prisma-client-go v0.31.4-0.20231228102837-d2b2373128a2 h1:8vofR6qaIWoTi2AGymk1MlipkUWLjBNjKjYA8DYaHps=
|
||||
github.com/steebchen/prisma-client-go v0.31.4-0.20231228102837-d2b2373128a2/go.mod h1:ksKELgUZSn56rbAv1jlF8D7o8V6lis0Tc2LEgv2qNbs=
|
||||
github.com/steebchen/prisma-client-go v0.32.1 h1:7jUke4XVSzUkV2TN4VhYSwjU7qizM9w475gpudkLCNI=
|
||||
github.com/steebchen/prisma-client-go v0.32.1/go.mod h1:shY2GTQyv15WYTE4p2zffr01ratTzX0zXtBWnDHiLpo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@@ -321,6 +337,10 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tink-crypto/tink-go v0.0.0-20230613075026-d6de17e3f164 h1:yhVO0Yhq84FjdcotvFFvDJRNHJ7mO743G12VdcW4Evc=
|
||||
github.com/tink-crypto/tink-go v0.0.0-20230613075026-d6de17e3f164/go.mod h1:HhtDVdE/PRZFRia834tkmcwuscnaAzda1RJUW9Pr3Rg=
|
||||
github.com/tink-crypto/tink-go-gcpkms v0.0.0-20230602082706-31d0d09ccc8d h1:+In5BwTMe2nF3FC6LrYqg71jDyaOOMZ4EQBFUhFq23g=
|
||||
github.com/tink-crypto/tink-go-gcpkms v0.0.0-20230602082706-31d0d09ccc8d/go.mod h1:TXKMH7TDt0h7QXtI9TdYPyly6xZL+ooPpbw30qekmEc=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
@@ -332,12 +352,17 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
|
||||
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
|
||||
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
|
||||
@@ -361,9 +386,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -401,6 +425,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -429,12 +454,12 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -458,8 +483,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
|
||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -498,15 +524,16 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -515,13 +542,14 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
@@ -569,6 +597,7 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -592,14 +621,17 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.157.0 h1:ORAeqmbrrozeyw5NjnMxh7peHO0UzV4wWYSwZeCUb20=
|
||||
google.golang.org/api v0.157.0/go.mod h1:+z4v4ufbZ1WEpld6yMGHyggs+PmAHiaLNj5ytP3N01g=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@@ -636,12 +668,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
|
||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f h1:2yNACc1O40tTnrsbk9Cv6oxiW8pxI/pXj0wRtdlYmgY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc=
|
||||
google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg=
|
||||
google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
@@ -658,8 +690,8 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
||||
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
||||
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
|
||||
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -672,8 +704,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
# This scripts generates a local API token.
|
||||
|
||||
set -eux
|
||||
|
||||
set -a
|
||||
. .env
|
||||
set +a
|
||||
|
||||
go run ./cmd/hatchet-admin token create --name "local" --tenant-id 707d0855-80ab-4e1f-a156-f1c4546cbf52
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
# This scripts generates local encryption keys for development.
|
||||
|
||||
set -eux
|
||||
|
||||
ENCRYPTION_KEYS_DIR=./encryption-keys
|
||||
|
||||
# Read CERTS_DIR from args if exists
|
||||
if [ -n "$1" ]; then
|
||||
ENCRYPTION_KEYS_DIR=$1
|
||||
fi
|
||||
|
||||
mkdir -p $ENCRYPTION_KEYS_DIR
|
||||
|
||||
# Generate a master encryption key
|
||||
go run ./cmd/hatchet-admin keyset create-local-keys --key-dir $ENCRYPTION_KEYS_DIR
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eux
|
||||
|
||||
set -a
|
||||
. .env
|
||||
set +a
|
||||
|
||||
go run ./cmd/temporal-server
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
cat > .env <<EOF
|
||||
TEMPORAL_CLIENT_TLS_ROOT_CA_FILE=./hack/dev/certs/ca.cert
|
||||
TEMPORAL_CLIENT_TLS_CERT_FILE=./hack/dev/certs/client-worker.pem
|
||||
TEMPORAL_CLIENT_TLS_KEY_FILE=./hack/dev/certs/client-worker.key
|
||||
TEMPORAL_CLIENT_TLS_SERVER_NAME=cluster
|
||||
|
||||
TEMPORAL_SQLITE_PATH=./temporal.db
|
||||
TEMPORAL_LOG_LEVEL=error
|
||||
|
||||
TEMPORAL_NAMESPACES=default
|
||||
|
||||
TEMPORAL_FRONTEND_TLS_SERVER_NAME=cluster
|
||||
TEMPORAL_FRONTEND_TLS_CERT_FILE=./hack/dev/certs/cluster.pem
|
||||
TEMPORAL_FRONTEND_TLS_KEY_FILE=./hack/dev/certs/cluster.key
|
||||
TEMPORAL_FRONTEND_TLS_ROOT_CA_FILE=./hack/dev/certs/ca.cert
|
||||
|
||||
TEMPORAL_WORKER_TLS_SERVER_NAME=cluster
|
||||
TEMPORAL_WORKER_TLS_CERT_FILE=./hack/dev/certs/cluster.pem
|
||||
TEMPORAL_WORKER_TLS_KEY_FILE=./hack/dev/certs/cluster.key
|
||||
TEMPORAL_WORKER_TLS_ROOT_CA_FILE=./hack/dev/certs/ca.cert
|
||||
|
||||
TEMPORAL_INTERNODE_TLS_SERVER_NAME=cluster
|
||||
TEMPORAL_INTERNODE_TLS_CERT_FILE=./hack/dev/certs/cluster.pem
|
||||
TEMPORAL_INTERNODE_TLS_KEY_FILE=./hack/dev/certs/cluster.key
|
||||
TEMPORAL_INTERNODE_TLS_ROOT_CA_FILE=./hack/dev/certs/ca.cert
|
||||
|
||||
TEMPORAL_UI_TLS_ROOT_CA_FILE=./hack/dev/certs/ca.cert
|
||||
TEMPORAL_UI_TLS_CERT_FILE=./hack/dev/certs/client-internal-admin.pem
|
||||
TEMPORAL_UI_TLS_KEY_FILE=./hack/dev/certs/client-internal-admin.key
|
||||
TEMPORAL_UI_TLS_SERVER_NAME=cluster
|
||||
EOF
|
||||
@@ -0,0 +1,163 @@
|
||||
package token
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/tink-crypto/tink-go/jwt"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/internal/encryption"
|
||||
"github.com/hatchet-dev/hatchet/internal/repository"
|
||||
)
|
||||
|
||||
type JWTManager interface {
|
||||
GenerateTenantToken(tenantId, name string) (string, error)
|
||||
ValidateTenantToken(token string) (string, error)
|
||||
}
|
||||
|
||||
type TokenOpts struct {
|
||||
Issuer string
|
||||
Audience string
|
||||
}
|
||||
|
||||
type jwtManagerImpl struct {
|
||||
encryption encryption.EncryptionService
|
||||
opts *TokenOpts
|
||||
tokenRepo repository.APITokenRepository
|
||||
verifier jwt.Verifier
|
||||
}
|
||||
|
||||
func NewJWTManager(encryptionSvc encryption.EncryptionService, tokenRepo repository.APITokenRepository, opts *TokenOpts) (JWTManager, error) {
|
||||
verifier, err := jwt.NewVerifier(encryptionSvc.GetPublicJWTHandle())
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create JWT Verifier: %v", err)
|
||||
}
|
||||
|
||||
return &jwtManagerImpl{
|
||||
encryption: encryptionSvc,
|
||||
opts: opts,
|
||||
tokenRepo: tokenRepo,
|
||||
verifier: verifier,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (j *jwtManagerImpl) GenerateTenantToken(tenantId, name string) (string, error) {
|
||||
// Retrieve the JWT Signer primitive from privateKeysetHandle.
|
||||
signer, err := jwt.NewSigner(j.encryption.GetPrivateJWTHandle())
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create JWT Signer: %v", err)
|
||||
}
|
||||
|
||||
tokenId, expiresAt, opts := j.getJWTOptionsForTenant(tenantId)
|
||||
|
||||
rawJWT, err := jwt.NewRawJWT(opts)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create raw JWT: %v", err)
|
||||
}
|
||||
|
||||
token, err := signer.SignAndEncode(rawJWT)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to sign and encode JWT: %v", err)
|
||||
}
|
||||
|
||||
// write the token to the database
|
||||
_, err = j.tokenRepo.CreateAPIToken(&repository.CreateAPITokenOpts{
|
||||
ID: tokenId,
|
||||
ExpiresAt: expiresAt,
|
||||
TenantId: &tenantId,
|
||||
Name: &name,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to write token to database: %v", err)
|
||||
}
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (j *jwtManagerImpl) ValidateTenantToken(token string) (tenantId string, err error) {
|
||||
// Verify the signed token.
|
||||
audience := j.opts.Audience
|
||||
|
||||
validator, err := jwt.NewValidator(&jwt.ValidatorOpts{
|
||||
ExpectedAudience: &audience,
|
||||
ExpectedIssuer: &j.opts.Issuer,
|
||||
FixedNow: time.Now(),
|
||||
ExpectIssuedInThePast: true,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create JWT Validator: %v", err)
|
||||
}
|
||||
|
||||
verifiedJwt, err := j.verifier.VerifyAndDecode(token, validator)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to verify and decode JWT: %v", err)
|
||||
}
|
||||
|
||||
// Read the token from the database and make sure it's not revoked
|
||||
if hasTokenId := verifiedJwt.HasStringClaim("token_id"); !hasTokenId {
|
||||
return "", fmt.Errorf("token does not have token_id claim")
|
||||
}
|
||||
|
||||
tokenId, err := verifiedJwt.StringClaim("token_id")
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read token_id claim: %v", err)
|
||||
}
|
||||
|
||||
// read the token from the database
|
||||
dbToken, err := j.tokenRepo.GetAPITokenById(tokenId)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read token from database: %v", err)
|
||||
}
|
||||
|
||||
if dbToken.Revoked {
|
||||
return "", fmt.Errorf("token has been revoked")
|
||||
}
|
||||
|
||||
if expiresAt, ok := dbToken.ExpiresAt(); ok && expiresAt.Before(time.Now()) {
|
||||
return "", fmt.Errorf("token has expired")
|
||||
}
|
||||
|
||||
// ensure the subject of the token matches the tenantId
|
||||
if hasSubject := verifiedJwt.HasSubject(); !hasSubject {
|
||||
return "", fmt.Errorf("token does not have subject claim")
|
||||
}
|
||||
|
||||
subject, err := verifiedJwt.Subject()
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to read subject claim: %v", err)
|
||||
}
|
||||
|
||||
return subject, nil
|
||||
}
|
||||
|
||||
func (j *jwtManagerImpl) getJWTOptionsForTenant(tenantId string) (tokenId string, expiresAt time.Time, opts *jwt.RawJWTOptions) {
|
||||
expiresAt = time.Now().Add(90 * 24 * time.Hour)
|
||||
iAt := time.Now()
|
||||
audience := j.opts.Audience
|
||||
subject := tenantId
|
||||
issuer := j.opts.Issuer
|
||||
tokenId = uuid.New().String()
|
||||
opts = &jwt.RawJWTOptions{
|
||||
IssuedAt: &iAt,
|
||||
Audience: &audience,
|
||||
Subject: &subject,
|
||||
ExpiresAt: &expiresAt,
|
||||
Issuer: &issuer,
|
||||
CustomClaims: map[string]interface{}{
|
||||
"token_id": tokenId,
|
||||
},
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
//go:build integration
|
||||
|
||||
package token_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/internal/auth/token"
|
||||
"github.com/hatchet-dev/hatchet/internal/config/database"
|
||||
"github.com/hatchet-dev/hatchet/internal/encryption"
|
||||
"github.com/hatchet-dev/hatchet/internal/repository"
|
||||
"github.com/hatchet-dev/hatchet/internal/testutils"
|
||||
)
|
||||
|
||||
func TestCreateTenantToken(t *testing.T) {
|
||||
testutils.RunTestWithDatabase(t, func(conf *database.Config) error {
|
||||
jwtManager := getJWTManager(t, conf)
|
||||
|
||||
tenantId := uuid.New().String()
|
||||
|
||||
// create the tenant
|
||||
slugSuffix, err := encryption.GenerateRandomBytes(8)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
_, err = conf.Repository.Tenant().CreateTenant(&repository.CreateTenantOpts{
|
||||
ID: &tenantId,
|
||||
Name: "test-tenant",
|
||||
Slug: fmt.Sprintf("test-tenant-%s", slugSuffix),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
token, err := jwtManager.GenerateTenantToken(tenantId, "test token")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
// validate the token
|
||||
newTenantId, err := jwtManager.ValidateTenantToken(token)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tenantId, newTenantId)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestRevokeTenantToken(t *testing.T) {
|
||||
testutils.RunTestWithDatabase(t, func(conf *database.Config) error {
|
||||
jwtManager := getJWTManager(t, conf)
|
||||
|
||||
tenantId := uuid.New().String()
|
||||
|
||||
// create the tenant
|
||||
slugSuffix, err := encryption.GenerateRandomBytes(8)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
_, err = conf.Repository.Tenant().CreateTenant(&repository.CreateTenantOpts{
|
||||
ID: &tenantId,
|
||||
Name: "test-tenant",
|
||||
Slug: fmt.Sprintf("test-tenant-%s", slugSuffix),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
token, err := jwtManager.GenerateTenantToken(tenantId, "test token")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
// validate the token
|
||||
_, err = jwtManager.ValidateTenantToken(token)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
// revoke the token
|
||||
apiTokens, err := conf.Repository.APIToken().ListAPITokensByTenant(tenantId)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
assert.Len(t, apiTokens, 1)
|
||||
err = conf.Repository.APIToken().RevokeAPIToken(apiTokens[0].ID)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
// validate the token again
|
||||
_, err = jwtManager.ValidateTenantToken(token)
|
||||
|
||||
assert.Error(t, err)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func getJWTManager(t *testing.T, conf *database.Config) token.JWTManager {
|
||||
t.Helper()
|
||||
|
||||
masterKeyBytes, privateJWTBytes, publicJWTBytes, err := encryption.GenerateLocalKeys()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
encryptionService, err := encryption.NewLocalEncryption(masterKeyBytes, privateJWTBytes, publicJWTBytes)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
tokenRepo := conf.Repository.APIToken()
|
||||
|
||||
jwtManager, err := token.NewJWTManager(encryptionService, tokenRepo, &token.TokenOpts{
|
||||
Issuer: "hatchet",
|
||||
Audience: "hatchet",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
return jwtManager
|
||||
}
|
||||
@@ -11,6 +11,10 @@ import (
|
||||
type ClientConfigFile struct {
|
||||
TenantId string `mapstructure:"tenantId" json:"tenantId,omitempty"`
|
||||
|
||||
Token string `mapstructure:"token" json:"token,omitempty"`
|
||||
|
||||
HostPort string `mapstructure:"hostPort" json:"hostPort,omitempty"`
|
||||
|
||||
TLS ClientTLSConfigFile `mapstructure:"tls" json:"tls,omitempty"`
|
||||
}
|
||||
|
||||
@@ -22,14 +26,18 @@ type ClientTLSConfigFile struct {
|
||||
|
||||
type ClientConfig struct {
|
||||
TenantId string
|
||||
Token string
|
||||
|
||||
TLSConfig *tls.Config
|
||||
}
|
||||
|
||||
func BindAllEnv(v *viper.Viper) {
|
||||
_ = v.BindEnv("tenantId", "HATCHET_CLIENT_TENANT_ID")
|
||||
_ = v.BindEnv("token", "HATCHET_CLIENT_TOKEN")
|
||||
_ = v.BindEnv("hostPort", "HATCHET_CLIENT_HOST_PORT")
|
||||
|
||||
// tls options
|
||||
_ = v.BindEnv("tls.base.tlsStrategy", "HATCHET_CLIENT_TLS_STRATEGY")
|
||||
_ = v.BindEnv("tls.base.tlsCertFile", "HATCHET_CLIENT_TLS_CERT_FILE")
|
||||
_ = v.BindEnv("tls.base.tlsKeyFile", "HATCHET_CLIENT_TLS_KEY_FILE")
|
||||
_ = v.BindEnv("tls.base.tlsRootCAFile", "HATCHET_CLIENT_TLS_ROOT_CA_FILE")
|
||||
|
||||
@@ -5,6 +5,7 @@ package loader
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
@@ -12,9 +13,11 @@ import (
|
||||
|
||||
"github.com/hatchet-dev/hatchet/internal/auth/cookie"
|
||||
"github.com/hatchet-dev/hatchet/internal/auth/oauth"
|
||||
"github.com/hatchet-dev/hatchet/internal/auth/token"
|
||||
"github.com/hatchet-dev/hatchet/internal/config/database"
|
||||
"github.com/hatchet-dev/hatchet/internal/config/loader/loaderutils"
|
||||
"github.com/hatchet-dev/hatchet/internal/config/server"
|
||||
"github.com/hatchet-dev/hatchet/internal/encryption"
|
||||
"github.com/hatchet-dev/hatchet/internal/logger"
|
||||
"github.com/hatchet-dev/hatchet/internal/repository/prisma"
|
||||
"github.com/hatchet-dev/hatchet/internal/repository/prisma/db"
|
||||
@@ -106,7 +109,7 @@ func GetDatabaseConfigFromConfigFile(cf *database.ConfigFile) (res *database.Con
|
||||
cf.PostgresSSLMode,
|
||||
)
|
||||
|
||||
// os.Setenv("DATABASE_URL", databaseUrl)
|
||||
os.Setenv("DATABASE_URL", databaseUrl)
|
||||
|
||||
client := db.NewClient(
|
||||
// db.WithDatasourceURL(databaseUrl),
|
||||
@@ -196,9 +199,26 @@ func GetServerConfigFromConfigfile(dc *database.Config, cf *server.ServerConfigF
|
||||
auth.GoogleOAuthConfig = gClient
|
||||
}
|
||||
|
||||
encryptionSvc, err := loadEncryptionSvc(cf)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not load encryption service: %w", err)
|
||||
}
|
||||
|
||||
// create a new JWT manager
|
||||
auth.JWTManager, err = token.NewJWTManager(encryptionSvc, dc.Repository.APIToken(), &token.TokenOpts{
|
||||
Issuer: cf.Runtime.ServerURL,
|
||||
Audience: cf.Runtime.ServerURL,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create JWT manager: %w", err)
|
||||
}
|
||||
|
||||
return &server.ServerConfig{
|
||||
Runtime: cf.Runtime,
|
||||
Auth: auth,
|
||||
Encryption: encryptionSvc,
|
||||
Config: dc,
|
||||
TaskQueue: tq,
|
||||
Services: cf.Services,
|
||||
@@ -214,3 +234,90 @@ func GetServerConfigFromConfigfile(dc *database.Config, cf *server.ServerConfigF
|
||||
func getStrArr(v string) []string {
|
||||
return strings.Split(v, " ")
|
||||
}
|
||||
|
||||
func loadEncryptionSvc(cf *server.ServerConfigFile) (encryption.EncryptionService, error) {
|
||||
var err error
|
||||
|
||||
hasLocalMasterKeyset := cf.Encryption.MasterKeyset != "" || cf.Encryption.MasterKeysetFile != ""
|
||||
isCloudKMSEnabled := cf.Encryption.CloudKMS.Enabled
|
||||
|
||||
if !hasLocalMasterKeyset && !isCloudKMSEnabled {
|
||||
return nil, fmt.Errorf("encryption is required")
|
||||
}
|
||||
|
||||
if hasLocalMasterKeyset && isCloudKMSEnabled {
|
||||
return nil, fmt.Errorf("cannot use both encryption and cloud kms")
|
||||
}
|
||||
|
||||
hasJWTKeys := (cf.Encryption.JWT.PublicJWTKeyset != "" || cf.Encryption.JWT.PublicJWTKeysetFile != "") &&
|
||||
(cf.Encryption.JWT.PrivateJWTKeyset != "" || cf.Encryption.JWT.PrivateJWTKeysetFile != "")
|
||||
|
||||
if !hasJWTKeys {
|
||||
return nil, fmt.Errorf("jwt encryption is required")
|
||||
}
|
||||
|
||||
privateJWT := cf.Encryption.JWT.PrivateJWTKeyset
|
||||
|
||||
if cf.Encryption.JWT.PrivateJWTKeysetFile != "" {
|
||||
privateJWTBytes, err := loaderutils.GetFileBytes(cf.Encryption.JWT.PrivateJWTKeysetFile)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not load private jwt keyset file: %w", err)
|
||||
}
|
||||
|
||||
privateJWT = string(privateJWTBytes)
|
||||
}
|
||||
|
||||
publicJWT := cf.Encryption.JWT.PublicJWTKeyset
|
||||
|
||||
if cf.Encryption.JWT.PublicJWTKeysetFile != "" {
|
||||
publicJWTBytes, err := loaderutils.GetFileBytes(cf.Encryption.JWT.PublicJWTKeysetFile)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not load public jwt keyset file: %w", err)
|
||||
}
|
||||
|
||||
publicJWT = string(publicJWTBytes)
|
||||
}
|
||||
|
||||
var encryptionSvc encryption.EncryptionService
|
||||
|
||||
if hasLocalMasterKeyset {
|
||||
masterKeyset := cf.Encryption.MasterKeyset
|
||||
|
||||
if cf.Encryption.MasterKeysetFile != "" {
|
||||
masterKeysetBytes, err := loaderutils.GetFileBytes(cf.Encryption.MasterKeysetFile)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not load master keyset file: %w", err)
|
||||
}
|
||||
|
||||
masterKeyset = string(masterKeysetBytes)
|
||||
}
|
||||
|
||||
encryptionSvc, err = encryption.NewLocalEncryption(
|
||||
[]byte(masterKeyset),
|
||||
[]byte(privateJWT),
|
||||
[]byte(publicJWT),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create raw keyset encryption service: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if isCloudKMSEnabled {
|
||||
encryptionSvc, err = encryption.NewCloudKMSEncryption(
|
||||
cf.Encryption.CloudKMS.KeyURI,
|
||||
[]byte(cf.Encryption.CloudKMS.CredentialsJSON),
|
||||
[]byte(privateJWT),
|
||||
[]byte(publicJWT),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create CloudKMS encryption service: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return encryptionSvc, nil
|
||||
}
|
||||
|
||||
@@ -21,6 +21,20 @@ func GetConfigBytes(configFilePath string) ([][]byte, error) {
|
||||
return configFileBytes, nil
|
||||
}
|
||||
|
||||
func GetFileBytes(filename string) ([]byte, error) {
|
||||
if fileExists(filename) {
|
||||
fileBytes, err := os.ReadFile(filename) // #nosec G304 -- config files are meant to be read from user-supplied directory
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read config file at path %s: %w", filename, err)
|
||||
}
|
||||
|
||||
return fileBytes, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("could not read config file at path %s", filename)
|
||||
}
|
||||
|
||||
func fileExists(filename string) bool {
|
||||
info, err := os.Stat(filename)
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
|
||||
@@ -10,15 +10,26 @@ import (
|
||||
"github.com/hatchet-dev/hatchet/internal/config/shared"
|
||||
)
|
||||
|
||||
func LoadClientTLSConfig(tlsConfig *client.ClientTLSConfigFile) (*tls.Config, error) {
|
||||
func LoadClientTLSConfig(tlsConfig *client.ClientTLSConfigFile, serverName string) (*tls.Config, error) {
|
||||
res, ca, err := LoadBaseTLSConfig(&tlsConfig.Base)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res.ServerName = tlsConfig.TLSServerName
|
||||
res.RootCAs = ca
|
||||
res.ServerName = serverName
|
||||
|
||||
switch tlsConfig.Base.TLSStrategy {
|
||||
case "tls":
|
||||
if ca != nil {
|
||||
res.RootCAs = ca
|
||||
}
|
||||
case "mtls":
|
||||
res.ServerName = tlsConfig.TLSServerName
|
||||
res.RootCAs = ca
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid TLS strategy: %s", tlsConfig.Base.TLSStrategy)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
@@ -30,8 +41,23 @@ func LoadServerTLSConfig(tlsConfig *shared.TLSConfigFile) (*tls.Config, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
res.ClientCAs = ca
|
||||
switch tlsConfig.TLSStrategy {
|
||||
case "tls":
|
||||
res.ClientAuth = tls.VerifyClientCertIfGiven
|
||||
|
||||
if ca != nil {
|
||||
res.ClientCAs = ca
|
||||
}
|
||||
case "mtls":
|
||||
if ca == nil {
|
||||
return nil, fmt.Errorf("Client CA is required for mTLS")
|
||||
}
|
||||
|
||||
res.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
res.ClientCAs = ca
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid TLS strategy: %s", tlsConfig.TLSStrategy)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
@@ -45,8 +71,6 @@ func LoadBaseTLSConfig(tlsConfig *shared.TLSConfigFile) (*tls.Config, *x509.Cert
|
||||
x509Cert, err = tls.X509KeyPair([]byte(tlsConfig.TLSCert), []byte(tlsConfig.TLSKey))
|
||||
case tlsConfig.TLSCertFile != "" && tlsConfig.TLSKeyFile != "":
|
||||
x509Cert, err = tls.LoadX509KeyPair(tlsConfig.TLSCertFile, tlsConfig.TLSKeyFile)
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("no cert or key provided")
|
||||
}
|
||||
|
||||
var caBytes []byte
|
||||
@@ -56,18 +80,25 @@ func LoadBaseTLSConfig(tlsConfig *shared.TLSConfigFile) (*tls.Config, *x509.Cert
|
||||
caBytes = []byte(tlsConfig.TLSRootCA)
|
||||
case tlsConfig.TLSRootCAFile != "":
|
||||
caBytes, err = os.ReadFile(tlsConfig.TLSRootCAFile)
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("no root CA provided")
|
||||
}
|
||||
|
||||
ca := x509.NewCertPool()
|
||||
var ca *x509.CertPool
|
||||
|
||||
if ok := ca.AppendCertsFromPEM(caBytes); !ok {
|
||||
return nil, nil, fmt.Errorf("could not append root CA to cert pool: %w", err)
|
||||
if len(caBytes) != 0 {
|
||||
ca = x509.NewCertPool()
|
||||
|
||||
if ok := ca.AppendCertsFromPEM(caBytes); !ok {
|
||||
return nil, nil, fmt.Errorf("could not append root CA to cert pool: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{x509Cert},
|
||||
MinVersion: tls.VersionTLS13,
|
||||
}, ca, nil
|
||||
res := &tls.Config{
|
||||
MinVersion: tls.VersionTLS13,
|
||||
}
|
||||
|
||||
if len(x509Cert.Certificate) != 0 {
|
||||
res.Certificates = []tls.Certificate{x509Cert}
|
||||
}
|
||||
|
||||
return res, ca, nil
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/internal/auth/cookie"
|
||||
"github.com/hatchet-dev/hatchet/internal/auth/token"
|
||||
"github.com/hatchet-dev/hatchet/internal/config/database"
|
||||
"github.com/hatchet-dev/hatchet/internal/config/shared"
|
||||
"github.com/hatchet-dev/hatchet/internal/encryption"
|
||||
"github.com/hatchet-dev/hatchet/internal/services/ingestor"
|
||||
"github.com/hatchet-dev/hatchet/internal/taskqueue"
|
||||
"github.com/hatchet-dev/hatchet/internal/validator"
|
||||
@@ -18,6 +20,8 @@ import (
|
||||
type ServerConfigFile struct {
|
||||
Auth ConfigFileAuth `mapstructure:"auth" json:"auth,omitempty"`
|
||||
|
||||
Encryption EncryptionConfigFile `mapstructure:"encryption" json:"encryption,omitempty"`
|
||||
|
||||
Runtime ConfigFileRuntime `mapstructure:"runtime" json:"runtime,omitempty"`
|
||||
|
||||
TaskQueue TaskQueueConfigFile `mapstructure:"taskQueue" json:"taskQueue,omitempty"`
|
||||
@@ -49,6 +53,49 @@ type ConfigFileRuntime struct {
|
||||
GRPCInsecure bool `mapstructure:"grpcInsecure" json:"grpcInsecure,omitempty" default:"false"`
|
||||
}
|
||||
|
||||
// Encryption options
|
||||
type EncryptionConfigFile struct {
|
||||
// MasterKeyset is the raw master keyset for the instance. This should be a base64-encoded JSON string. You must set
|
||||
// either MasterKeyset, MasterKeysetFile or cloudKms.enabled with CloudKMS credentials
|
||||
MasterKeyset string `mapstructure:"masterKeyset" json:"masterKeyset,omitempty"`
|
||||
|
||||
// MasterKeysetFile is the path to the master keyset file for the instance.
|
||||
MasterKeysetFile string `mapstructure:"masterKeysetFile" json:"masterKeysetFile,omitempty"`
|
||||
|
||||
JWT EncryptionConfigFileJWT `mapstructure:"jwt" json:"jwt,omitempty"`
|
||||
|
||||
// CloudKMS is the configuration for Google Cloud KMS. You must set either MasterKeyset or cloudKms.enabled.
|
||||
CloudKMS EncryptionConfigFileCloudKMS `mapstructure:"cloudKms" json:"cloudKms,omitempty"`
|
||||
}
|
||||
|
||||
type EncryptionConfigFileJWT struct {
|
||||
// PublicJWTKeyset is a base64-encoded JSON string containing the public keyset which has been encrypted
|
||||
// by the master key.
|
||||
PublicJWTKeyset string `mapstructure:"publicJWTKeyset" json:"publicJWTKeyset,omitempty"`
|
||||
|
||||
// PublicJWTKeysetFile is the path to the public keyset file for the instance.
|
||||
PublicJWTKeysetFile string `mapstructure:"publicJWTKeysetFile" json:"publicJWTKeysetFile,omitempty"`
|
||||
|
||||
// PrivateJWTKeyset is a base64-encoded JSON string containing the private keyset which has been encrypted
|
||||
// by the master key.
|
||||
PrivateJWTKeyset string `mapstructure:"privateJWTKeyset" json:"privateJWTKeyset,omitempty"`
|
||||
|
||||
// PrivateJWTKeysetFile is the path to the private keyset file for the instance.
|
||||
PrivateJWTKeysetFile string `mapstructure:"privateJWTKeysetFile" json:"privateJWTKeysetFile,omitempty"`
|
||||
}
|
||||
|
||||
type EncryptionConfigFileCloudKMS struct {
|
||||
// Enabled controls whether the Cloud KMS service is enabled for this Hatchet instance.
|
||||
Enabled bool `mapstructure:"enabled" json:"enabled,omitempty" default:"false"`
|
||||
|
||||
// KeyURI is the URI of the key in Google Cloud KMS. This should be in the format of
|
||||
// gcp-kms://...
|
||||
KeyURI string `mapstructure:"keyURI" json:"keyURI,omitempty"`
|
||||
|
||||
// CredentialsJSON is the JSON credentials for the Google Cloud KMS service account.
|
||||
CredentialsJSON string `mapstructure:"credentialsJSON" json:"credentialsJSON,omitempty"`
|
||||
}
|
||||
|
||||
type ConfigFileAuth struct {
|
||||
// RestrictedEmailDomains sets the restricted email domains for the instance.
|
||||
RestrictedEmailDomains []string `mapstructure:"restrictedEmailDomains" json:"restrictedEmailDomains,omitempty"`
|
||||
@@ -95,6 +142,8 @@ type AuthConfig struct {
|
||||
ConfigFile ConfigFileAuth
|
||||
|
||||
GoogleOAuthConfig *oauth2.Config
|
||||
|
||||
JWTManager token.JWTManager
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
@@ -102,6 +151,8 @@ type ServerConfig struct {
|
||||
|
||||
Auth AuthConfig
|
||||
|
||||
Encryption encryption.EncryptionService
|
||||
|
||||
Runtime ConfigFileRuntime
|
||||
|
||||
Services []string
|
||||
@@ -142,6 +193,17 @@ func BindAllEnv(v *viper.Viper) {
|
||||
_ = v.BindEnv("runtime.grpcInsecure", "SERVER_GRPC_INSECURE")
|
||||
_ = v.BindEnv("services", "SERVER_SERVICES")
|
||||
|
||||
// encryption options
|
||||
_ = v.BindEnv("encryption.masterKeyset", "SERVER_ENCRYPTION_MASTER_KEYSET")
|
||||
_ = v.BindEnv("encryption.masterKeysetFile", "SERVER_ENCRYPTION_MASTER_KEYSET_FILE")
|
||||
_ = v.BindEnv("encryption.jwt.publicJWTKeyset", "SERVER_ENCRYPTION_JWT_PUBLIC_KEYSET")
|
||||
_ = v.BindEnv("encryption.jwt.publicJWTKeysetFile", "SERVER_ENCRYPTION_JWT_PUBLIC_KEYSET_FILE")
|
||||
_ = v.BindEnv("encryption.jwt.privateJWTKeyset", "SERVER_ENCRYPTION_JWT_PRIVATE_KEYSET")
|
||||
_ = v.BindEnv("encryption.jwt.privateJWTKeysetFile", "SERVER_ENCRYPTION_JWT_PRIVATE_KEYSET_FILE")
|
||||
_ = v.BindEnv("encryption.cloudKms.enabled", "SERVER_ENCRYPTION_CLOUDKMS_ENABLED")
|
||||
_ = v.BindEnv("encryption.cloudKms.keyURI", "SERVER_ENCRYPTION_CLOUDKMS_KEY_URI")
|
||||
_ = v.BindEnv("encryption.cloudKms.credentialsJSON", "SERVER_ENCRYPTION_CLOUDKMS_CREDENTIALS_JSON")
|
||||
|
||||
// auth options
|
||||
_ = v.BindEnv("auth.restrictedEmailDomains", "SERVER_AUTH_RESTRICTED_EMAIL_DOMAINS")
|
||||
_ = v.BindEnv("auth.basicAuthEnabled", "SERVER_AUTH_BASIC_AUTH_ENABLED")
|
||||
@@ -160,6 +222,7 @@ func BindAllEnv(v *viper.Viper) {
|
||||
_ = v.BindEnv("taskQueue.rabbitmq.url", "SERVER_TASKQUEUE_RABBITMQ_URL")
|
||||
|
||||
// tls options
|
||||
_ = v.BindEnv("tls.tlsStrategy", "SERVER_TLS_STRATEGY")
|
||||
_ = v.BindEnv("tls.tlsCert", "SERVER_TLS_CERT")
|
||||
_ = v.BindEnv("tls.tlsCertFile", "SERVER_TLS_CERT_FILE")
|
||||
_ = v.BindEnv("tls.tlsKey", "SERVER_TLS_KEY")
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package shared
|
||||
|
||||
type TLSConfigFile struct {
|
||||
// TLSStrategy can be "tls" or "mtls"
|
||||
TLSStrategy string `mapstructure:"tlsStrategy" json:"tlsStrategy,omitempty" default:"tls"`
|
||||
|
||||
TLSCert string `mapstructure:"tlsCert" json:"tlsCert,omitempty"`
|
||||
TLSCertFile string `mapstructure:"tlsCertFile" json:"tlsCertFile,omitempty"`
|
||||
TLSKey string `mapstructure:"tlsKey" json:"tlsKey,omitempty"`
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// This file is copied from: https://github.com/gtank/cryptopasta
|
||||
|
||||
// NewEncryptionKey generates a random 256-bit key for Encrypt() and
|
||||
// Decrypt(). It panics if the source of randomness fails.
|
||||
func NewEncryptionKey() *[32]byte {
|
||||
key := [32]byte{}
|
||||
_, err := io.ReadFull(rand.Reader, key[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &key
|
||||
}
|
||||
|
||||
// Encrypt encrypts data using 256-bit AES-GCM. This both hides the content of
|
||||
// the data and provides a check that it hasn't been altered. Output takes the
|
||||
// form nonce|ciphertext|tag where '|' indicates concatenation.
|
||||
func Encrypt(plaintext []byte, key *[32]byte) (ciphertext []byte, err error) {
|
||||
block, err := aes.NewCipher(key[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
_, err = io.ReadFull(rand.Reader, nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return gcm.Seal(nonce, nonce, plaintext, nil), nil
|
||||
}
|
||||
|
||||
// Decrypt decrypts data using 256-bit AES-GCM. This both hides the content of
|
||||
// the data and provides a check that it hasn't been altered. Expects input
|
||||
// form nonce|ciphertext|tag where '|' indicates concatenation.
|
||||
func Decrypt(ciphertext []byte, key *[32]byte) (plaintext []byte, err error) {
|
||||
block, err := aes.NewCipher(key[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(ciphertext) < gcm.NonceSize() {
|
||||
return nil, errors.New("malformed ciphertext")
|
||||
}
|
||||
|
||||
return gcm.Open(nil,
|
||||
ciphertext[:gcm.NonceSize()],
|
||||
ciphertext[gcm.NonceSize():],
|
||||
nil,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/tink-crypto/tink-go-gcpkms/integration/gcpkms"
|
||||
"github.com/tink-crypto/tink-go/aead"
|
||||
"github.com/tink-crypto/tink-go/core/registry"
|
||||
"github.com/tink-crypto/tink-go/keyset"
|
||||
"google.golang.org/api/option"
|
||||
)
|
||||
|
||||
type cloudkmsEncryptionService struct {
|
||||
key *aead.KMSEnvelopeAEAD
|
||||
privateEc256Handle *keyset.Handle
|
||||
publicEc256Handle *keyset.Handle
|
||||
}
|
||||
|
||||
// NewCloudKMSEncryption creates a GCP CloudKMS-backed encryption service.
|
||||
func NewCloudKMSEncryption(keyUri string, credentialsJSON, privateEc256, publicEc256 []byte) (*cloudkmsEncryptionService, error) {
|
||||
client, err := gcpkms.NewClientWithOptions(context.Background(), keyUri, option.WithCredentialsJSON(credentialsJSON))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newWithClient(client, keyUri, privateEc256, publicEc256)
|
||||
}
|
||||
|
||||
func GenerateJWTKeysetsFromCloudKMS(keyUri string, credentialsJSON []byte) (privateEc256 []byte, publicEc256 []byte, err error) {
|
||||
client, err := gcpkms.NewClientWithOptions(context.Background(), keyUri, option.WithCredentialsJSON(credentialsJSON))
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return generateJWTKeysetsWithClient(keyUri, client)
|
||||
}
|
||||
|
||||
func generateJWTKeysetsWithClient(keyUri string, client registry.KMSClient) (privateEc256 []byte, publicEc256 []byte, err error) {
|
||||
registry.RegisterKMSClient(client)
|
||||
|
||||
remote, err := client.GetAEAD(keyUri)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return generateJWTKeysets(remote)
|
||||
}
|
||||
|
||||
func newWithClient(client registry.KMSClient, keyUri string, privateEc256, publicEc256 []byte) (*cloudkmsEncryptionService, error) {
|
||||
registry.RegisterKMSClient(client)
|
||||
|
||||
dek := aead.AES128CTRHMACSHA256KeyTemplate()
|
||||
template, err := aead.CreateKMSEnvelopeAEADKeyTemplate(keyUri, dek)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// get the remote KEK from the client
|
||||
remote, err := client.GetAEAD(keyUri)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
envelope := aead.NewKMSEnvelopeAEAD2(template, remote)
|
||||
|
||||
if envelope == nil {
|
||||
return nil, fmt.Errorf("failed to create envelope")
|
||||
}
|
||||
|
||||
privateEc256Handle, err := handleFromBytes(privateEc256, remote)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
publicEc256Handle, err := handleFromBytes(publicEc256, remote)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &cloudkmsEncryptionService{
|
||||
key: envelope,
|
||||
privateEc256Handle: privateEc256Handle,
|
||||
publicEc256Handle: publicEc256Handle,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (svc *cloudkmsEncryptionService) Encrypt(plaintext []byte, dataId string) ([]byte, error) {
|
||||
return encrypt(svc.key, plaintext, dataId)
|
||||
}
|
||||
|
||||
func (svc *cloudkmsEncryptionService) Decrypt(ciphertext []byte, dataId string) ([]byte, error) {
|
||||
return decrypt(svc.key, ciphertext, dataId)
|
||||
}
|
||||
|
||||
func (svc *cloudkmsEncryptionService) GetPrivateJWTHandle() *keyset.Handle {
|
||||
return svc.privateEc256Handle
|
||||
}
|
||||
|
||||
func (svc *cloudkmsEncryptionService) GetPublicJWTHandle() *keyset.Handle {
|
||||
return svc.publicEc256Handle
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tink-crypto/tink-go/testing/fakekms"
|
||||
)
|
||||
|
||||
var (
|
||||
fakeKeyURI = "fake-kms://CM2b3_MDElQKSAowdHlwZS5nb29nbGVhcGlzLmNvbS9nb29nbGUuY3J5cHRvLnRpbmsuQWVzR2NtS2V5EhIaEIK75t5L-adlUwVhWvRuWUwYARABGM2b3_MDIAE"
|
||||
fakeCredentialsJSON = []byte(`{}`)
|
||||
)
|
||||
|
||||
func TestNewCloudKMSEncryptionValid(t *testing.T) {
|
||||
// Using fake KMS client for testing
|
||||
client, err := fakekms.NewClient(fakeKeyURI)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// generate JWT keysets
|
||||
privateEc256, publicEc256, err := generateJWTKeysetsWithClient(fakeKeyURI, client)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create encryption service with valid key URI and credentials
|
||||
svc, err := newWithClient(client, fakeKeyURI, privateEc256, publicEc256)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, svc)
|
||||
}
|
||||
|
||||
func TestNewCloudKMSEncryptionInvalidKeyUri(t *testing.T) {
|
||||
// Create encryption service with invalid key URI
|
||||
_, err := NewCloudKMSEncryption("invalid-key-uri", fakeCredentialsJSON, nil, nil)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestNewCloudKMSEncryptionInvalidCredentials(t *testing.T) {
|
||||
// Create encryption service with invalid credentials
|
||||
_, err := NewCloudKMSEncryption(fakeKeyURI, []byte("invalid credentials"), nil, nil)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestEncryptDecryptCloudKMS(t *testing.T) {
|
||||
// Using fake KMS client for testing
|
||||
client, err := fakekms.NewClient(fakeKeyURI)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// generate JWT keysets
|
||||
privateEc256, publicEc256, err := generateJWTKeysetsWithClient(fakeKeyURI, client)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create encryption service with valid key URI and credentials
|
||||
svc, err := newWithClient(client, fakeKeyURI, privateEc256, publicEc256)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
plaintext := []byte("test message")
|
||||
dataID := "123"
|
||||
|
||||
// Encrypt
|
||||
ciphertext, err := svc.Encrypt(plaintext, dataID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Decrypt
|
||||
decryptedText, err := svc.Decrypt(ciphertext, dataID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check if decrypted text matches original plaintext
|
||||
assert.Equal(t, plaintext, decryptedText)
|
||||
}
|
||||
|
||||
func TestEncryptDecryptCloudKMSWithEmptyDataID(t *testing.T) {
|
||||
// Using fake KMS client for testing
|
||||
client, err := fakekms.NewClient(fakeKeyURI)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// generate JWT keysets
|
||||
privateEc256, publicEc256, err := generateJWTKeysetsWithClient(fakeKeyURI, client)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create encryption service with valid key URI and credentials
|
||||
svc, err := newWithClient(client, fakeKeyURI, privateEc256, publicEc256)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
plaintext := []byte("test message")
|
||||
emptyDataID := ""
|
||||
|
||||
// Encrypt with empty data ID
|
||||
_, err = svc.Encrypt(plaintext, emptyDataID)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/tink-crypto/tink-go/tink"
|
||||
)
|
||||
|
||||
func encrypt(key tink.AEAD, plaintext []byte, dataId string) ([]byte, error) {
|
||||
// validate data id is not empty
|
||||
if len(dataId) == 0 {
|
||||
return nil, fmt.Errorf("data id cannot be empty")
|
||||
}
|
||||
|
||||
associatedData := []byte(dataId)
|
||||
|
||||
// encrypt the data
|
||||
return key.Encrypt(plaintext, associatedData)
|
||||
}
|
||||
|
||||
func decrypt(key tink.AEAD, ciphertext []byte, dataId string) ([]byte, error) {
|
||||
// validate data id is not empty
|
||||
if len(dataId) == 0 {
|
||||
return nil, fmt.Errorf("data id cannot be empty")
|
||||
}
|
||||
|
||||
associatedData := []byte(dataId)
|
||||
|
||||
// decrypt the data
|
||||
return key.Decrypt(ciphertext, associatedData)
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/tink-crypto/tink-go/aead"
|
||||
"github.com/tink-crypto/tink-go/insecurecleartextkeyset"
|
||||
"github.com/tink-crypto/tink-go/jwt"
|
||||
"github.com/tink-crypto/tink-go/keyset"
|
||||
"github.com/tink-crypto/tink-go/tink"
|
||||
)
|
||||
|
||||
type localEncryptionService struct {
|
||||
key *aead.KMSEnvelopeAEAD
|
||||
privateEc256Handle *keyset.Handle
|
||||
publicEc256Handle *keyset.Handle
|
||||
}
|
||||
|
||||
// NewLocalEncryption creates a new local encryption service. keysetBytes is the raw keyset in
|
||||
// base64-encoded JSON format. This can be generated by calling hatchet-admin keyset create-local.
|
||||
func NewLocalEncryption(masterKey []byte, privateEc256 []byte, publicEc256 []byte) (*localEncryptionService, error) {
|
||||
// get the master keyset handle
|
||||
aes256GcmHandle, err := insecureHandleFromBytes(masterKey)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
a, err := aead.New(aes256GcmHandle)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
privateEc256Handle, err := handleFromBytes(privateEc256, a)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
publicEc256Handle, err := handleFromBytes(publicEc256, a)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
envelope := aead.NewKMSEnvelopeAEAD2(aead.AES128GCMKeyTemplate(), a)
|
||||
|
||||
if envelope == nil {
|
||||
return nil, fmt.Errorf("failed to create envelope")
|
||||
}
|
||||
|
||||
return &localEncryptionService{
|
||||
key: envelope,
|
||||
privateEc256Handle: privateEc256Handle,
|
||||
publicEc256Handle: publicEc256Handle,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GenerateLocalKeys() (masterKey []byte, privateEc256 []byte, publicEc256 []byte, err error) {
|
||||
masterKey, masterHandle, err := generateLocalMasterKey()
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
a, err := aead.New(masterHandle)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
privateEc256, publicEc256, err = generateJWTKeysets(a)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
return masterKey, privateEc256, publicEc256, nil
|
||||
}
|
||||
|
||||
func generateLocalMasterKey() ([]byte, *keyset.Handle, error) {
|
||||
aeadTemplate := aead.AES256GCMKeyTemplate()
|
||||
|
||||
aes256GcmHandle, err := keyset.NewHandle(aeadTemplate)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create new keyset handle with AES256GCM template: %w", err)
|
||||
}
|
||||
|
||||
bytes, err := insecureBytesFromHandle(aes256GcmHandle)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to get bytes from handle: %w", err)
|
||||
}
|
||||
|
||||
return bytes, aes256GcmHandle, nil
|
||||
}
|
||||
|
||||
// generateJWTKeysets creates the keysets for JWT signing and verification encrypted with the
|
||||
// masterKey. The masterKey can be from a remote KMS service or a local keyset.
|
||||
func generateJWTKeysets(masterKey tink.AEAD) (privateEc256 []byte, publicEc256 []byte, err error) {
|
||||
privateHandle, err := keyset.NewHandle(jwt.ES256Template())
|
||||
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to create new keyset handle with ES256 template: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
privateEc256, err = bytesFromHandle(privateHandle, masterKey)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
publicHandle, err := privateHandle.Public()
|
||||
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to get public keyset: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
publicEc256, err = bytesFromHandle(publicHandle, masterKey)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// bytesFromHandle returns the encrypted keyset in base64-encoded JSON format, encrypted with the
|
||||
// masterKey
|
||||
func bytesFromHandle(kh *keyset.Handle, masterKey tink.AEAD) ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
writer := keyset.NewJSONWriter(buf)
|
||||
err := kh.Write(writer, masterKey)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to write keyset: %w", err)
|
||||
}
|
||||
|
||||
// base64-encode bytes
|
||||
keysetBytes := make([]byte, base64.RawStdEncoding.EncodedLen(len(buf.Bytes())))
|
||||
base64.RawStdEncoding.Encode(keysetBytes, buf.Bytes())
|
||||
|
||||
return keysetBytes, nil
|
||||
}
|
||||
|
||||
// insecureBytesFromHandle returns the raw (unencrypted) keyset in base64-encoded JSON format.
|
||||
func insecureBytesFromHandle(kh *keyset.Handle) ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
writer := keyset.NewJSONWriter(buf)
|
||||
err := insecurecleartextkeyset.Write(kh, writer)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to write keyset: %w", err)
|
||||
}
|
||||
|
||||
// base64-encode bytes
|
||||
keysetBytes := make([]byte, base64.RawStdEncoding.EncodedLen(len(buf.Bytes())))
|
||||
base64.RawStdEncoding.Encode(keysetBytes, buf.Bytes())
|
||||
|
||||
return keysetBytes, nil
|
||||
}
|
||||
|
||||
func handleFromBytes(keysetBytes []byte, masterKey tink.AEAD) (*keyset.Handle, error) {
|
||||
// base64-decode bytes
|
||||
keysetJsonBytes := make([]byte, base64.RawStdEncoding.DecodedLen(len(keysetBytes)))
|
||||
_, err := base64.RawStdEncoding.Decode(keysetJsonBytes, keysetBytes)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode keyset bytes: %w", err)
|
||||
}
|
||||
|
||||
// read keyset
|
||||
handle, err := keyset.Read(keyset.NewJSONReader(bytes.NewReader(keysetJsonBytes)), masterKey)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read keyset: %w", err)
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
func insecureHandleFromBytes(keysetBytes []byte) (*keyset.Handle, error) {
|
||||
// base64-decode bytes
|
||||
keysetJsonBytes := make([]byte, base64.RawStdEncoding.DecodedLen(len(keysetBytes)))
|
||||
_, err := base64.RawStdEncoding.Decode(keysetJsonBytes, keysetBytes)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode keyset bytes: %w", err)
|
||||
}
|
||||
|
||||
// read keyset
|
||||
handle, err := insecurecleartextkeyset.Read(keyset.NewJSONReader(bytes.NewReader(keysetJsonBytes)))
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read keyset: %w", err)
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
func (svc *localEncryptionService) Encrypt(plaintext []byte, dataId string) ([]byte, error) {
|
||||
return encrypt(svc.key, plaintext, dataId)
|
||||
}
|
||||
|
||||
func (svc *localEncryptionService) Decrypt(ciphertext []byte, dataId string) ([]byte, error) {
|
||||
return decrypt(svc.key, ciphertext, dataId)
|
||||
}
|
||||
|
||||
func (svc *localEncryptionService) GetPrivateJWTHandle() *keyset.Handle {
|
||||
return svc.privateEc256Handle
|
||||
}
|
||||
|
||||
func (svc *localEncryptionService) GetPublicJWTHandle() *keyset.Handle {
|
||||
return svc.publicEc256Handle
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewLocalEncryptionValidKeyset(t *testing.T) {
|
||||
// Generate a new keyset
|
||||
aes256Gcm, privateEc256, publicEc256, err := GenerateLocalKeys()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Create encryption service
|
||||
_, err = NewLocalEncryption(aes256Gcm, privateEc256, publicEc256)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestNewLocalEncryptionInvalidKeyset(t *testing.T) {
|
||||
invalidKeysetBytes := []byte("invalid keyset")
|
||||
|
||||
// Create encryption service with invalid keyset
|
||||
_, err := NewLocalEncryption(invalidKeysetBytes, invalidKeysetBytes, invalidKeysetBytes)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestEncryptDecrypt(t *testing.T) {
|
||||
aes256Gcm, privateEc256, publicEc256, _ := GenerateLocalKeys()
|
||||
svc, _ := NewLocalEncryption(aes256Gcm, privateEc256, publicEc256)
|
||||
|
||||
plaintext := []byte("test message")
|
||||
dataID := "123"
|
||||
|
||||
// Encrypt
|
||||
ciphertext, err := svc.Encrypt(plaintext, dataID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Decrypt
|
||||
decryptedText, err := svc.Decrypt(ciphertext, dataID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check if decrypted text matches original plaintext
|
||||
assert.Equal(t, plaintext, decryptedText)
|
||||
}
|
||||
|
||||
func TestDecryptWithInvalidKey(t *testing.T) {
|
||||
aes256Gcm, privateEc256, publicEc256, _ := GenerateLocalKeys()
|
||||
svc, _ := NewLocalEncryption(aes256Gcm, privateEc256, publicEc256)
|
||||
|
||||
plaintext := []byte("test message")
|
||||
dataID := "123"
|
||||
|
||||
// Encrypt
|
||||
ciphertext, _ := svc.Encrypt(plaintext, dataID)
|
||||
|
||||
// Generate a new keyset for decryption
|
||||
aes256Gcm, privateEc256, publicEc256, _ = GenerateLocalKeys()
|
||||
newSvc, _ := NewLocalEncryption(aes256Gcm, privateEc256, publicEc256)
|
||||
|
||||
// Attempt to decrypt with a different key
|
||||
_, err := newSvc.Decrypt(ciphertext, dataID)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestEncryptDecryptWithEmptyDataID(t *testing.T) {
|
||||
aes256Gcm, privateEc256, publicEc256, _ := GenerateLocalKeys()
|
||||
svc, _ := NewLocalEncryption(aes256Gcm, privateEc256, publicEc256)
|
||||
|
||||
plaintext := []byte("test message")
|
||||
emptyDataID := ""
|
||||
|
||||
// Encrypt with empty data ID
|
||||
_, err := svc.Encrypt(plaintext, emptyDataID)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Decrypt with empty data ID
|
||||
_, err = svc.Decrypt(plaintext, emptyDataID)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package encryption
|
||||
|
||||
import "github.com/tink-crypto/tink-go/keyset"
|
||||
|
||||
type EncryptionService interface {
|
||||
// Encrypt encrypts the given plaintext with the given data id. The data id is used to
|
||||
// associate the ciphertext with the data in the database.
|
||||
// For more information, see: https://developers.google.com/tink/client-side-encryption#kms_envelope_aead
|
||||
Encrypt(plaintext []byte, dataId string) ([]byte, error)
|
||||
|
||||
// Decrypt decrypts the given ciphertext with the given data id. The data id is used to
|
||||
// associate the ciphertext with the data in the database.
|
||||
// For more information, see: https://developers.google.com/tink/client-side-encryption#kms_envelope_aead
|
||||
Decrypt(ciphertext []byte, dataId string) ([]byte, error)
|
||||
|
||||
// GetPrivateJWTHandle returns a private JWT handle. This is used to sign JWTs.
|
||||
GetPrivateJWTHandle() *keyset.Handle
|
||||
|
||||
// GetPublicJWTHandle returns a public JWT handle. This is used to verify JWTs.
|
||||
GetPublicJWTHandle() *keyset.Handle
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/internal/repository/prisma/db"
|
||||
)
|
||||
|
||||
type CreateAPITokenOpts struct {
|
||||
// The id of the token
|
||||
ID string `validate:"required,uuid"`
|
||||
|
||||
// When the token expires
|
||||
ExpiresAt time.Time
|
||||
|
||||
// (optional) A tenant ID for this API token
|
||||
TenantId *string `validate:"omitempty,uuid"`
|
||||
|
||||
// (optional) A name for this API token
|
||||
Name *string `validate:"omitempty,max=255"`
|
||||
}
|
||||
|
||||
type APITokenRepository interface {
|
||||
GetAPITokenById(id string) (*db.APITokenModel, error)
|
||||
CreateAPIToken(opts *CreateAPITokenOpts) (*db.APITokenModel, error)
|
||||
RevokeAPIToken(id string) error
|
||||
ListAPITokensByTenant(tenantId string) ([]db.APITokenModel, error)
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package prisma
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/internal/repository"
|
||||
"github.com/hatchet-dev/hatchet/internal/repository/prisma/db"
|
||||
"github.com/hatchet-dev/hatchet/internal/validator"
|
||||
)
|
||||
|
||||
type apiTokenRepository struct {
|
||||
client *db.PrismaClient
|
||||
v validator.Validator
|
||||
}
|
||||
|
||||
func NewAPITokenRepository(client *db.PrismaClient, v validator.Validator) repository.APITokenRepository {
|
||||
return &apiTokenRepository{
|
||||
client: client,
|
||||
v: v,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *apiTokenRepository) GetAPITokenById(id string) (*db.APITokenModel, error) {
|
||||
return a.client.APIToken.FindUnique(
|
||||
db.APIToken.ID.Equals(id),
|
||||
).Exec(context.Background())
|
||||
}
|
||||
|
||||
func (a *apiTokenRepository) CreateAPIToken(opts *repository.CreateAPITokenOpts) (*db.APITokenModel, error) {
|
||||
if err := a.v.Validate(opts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
optionals := []db.APITokenSetParam{
|
||||
db.APIToken.ID.Set(opts.ID),
|
||||
db.APIToken.ExpiresAt.Set(opts.ExpiresAt),
|
||||
}
|
||||
|
||||
if opts.TenantId != nil {
|
||||
optionals = append(optionals, db.APIToken.Tenant.Link(
|
||||
db.Tenant.ID.Equals(*opts.TenantId),
|
||||
))
|
||||
}
|
||||
|
||||
if opts.Name != nil {
|
||||
optionals = append(optionals, db.APIToken.Name.Set(*opts.Name))
|
||||
}
|
||||
|
||||
return a.client.APIToken.CreateOne(
|
||||
optionals...,
|
||||
).Exec(context.Background())
|
||||
}
|
||||
|
||||
func (a *apiTokenRepository) RevokeAPIToken(id string) error {
|
||||
_, err := a.client.APIToken.FindUnique(
|
||||
db.APIToken.ID.Equals(id),
|
||||
).Update(
|
||||
db.APIToken.ExpiresAt.Set(time.Now().Add(-1*time.Second)),
|
||||
db.APIToken.Revoked.Set(true),
|
||||
).Exec(context.Background())
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *apiTokenRepository) ListAPITokensByTenant(tenantId string) ([]db.APITokenModel, error) {
|
||||
return a.client.APIToken.FindMany(
|
||||
db.APIToken.TenantID.Equals(tenantId),
|
||||
db.APIToken.Revoked.Equals(false),
|
||||
).Exec(context.Background())
|
||||
}
|
||||
@@ -275,14 +275,25 @@ func (ns NullWorkflowRunStatus) Value() (driver.Value, error) {
|
||||
return string(ns.WorkflowRunStatus), nil
|
||||
}
|
||||
|
||||
type APIToken struct {
|
||||
ID pgtype.UUID `json:"id"`
|
||||
CreatedAt pgtype.Timestamp `json:"createdAt"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updatedAt"`
|
||||
ExpiresAt pgtype.Timestamp `json:"expiresAt"`
|
||||
Revoked bool `json:"revoked"`
|
||||
Name pgtype.Text `json:"name"`
|
||||
TenantId pgtype.UUID `json:"tenantId"`
|
||||
}
|
||||
|
||||
type Action struct {
|
||||
ID string `json:"id"`
|
||||
ID pgtype.UUID `json:"id"`
|
||||
ActionId string `json:"actionId"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
TenantId pgtype.UUID `json:"tenantId"`
|
||||
}
|
||||
|
||||
type ActionToWorker struct {
|
||||
A string `json:"A"`
|
||||
A pgtype.UUID `json:"A"`
|
||||
B pgtype.UUID `json:"B"`
|
||||
}
|
||||
|
||||
@@ -464,8 +475,8 @@ type UserOAuth struct {
|
||||
UserId pgtype.UUID `json:"userId"`
|
||||
Provider string `json:"provider"`
|
||||
ProviderUserId string `json:"providerUserId"`
|
||||
AccessToken string `json:"accessToken"`
|
||||
RefreshToken pgtype.Text `json:"refreshToken"`
|
||||
AccessToken []byte `json:"accessToken"`
|
||||
RefreshToken []byte `json:"refreshToken"`
|
||||
ExpiresAt pgtype.Timestamp `json:"expiresAt"`
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,23 @@ CREATE TYPE "WorkerStatus" AS ENUM ('ACTIVE', 'INACTIVE');
|
||||
-- CreateEnum
|
||||
CREATE TYPE "WorkflowRunStatus" AS ENUM ('PENDING', 'RUNNING', 'SUCCEEDED', 'FAILED');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "APIToken" (
|
||||
"id" UUID NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"expiresAt" TIMESTAMP(3),
|
||||
"revoked" BOOLEAN NOT NULL DEFAULT false,
|
||||
"name" TEXT,
|
||||
"tenantId" UUID,
|
||||
|
||||
CONSTRAINT "APIToken_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Action" (
|
||||
"id" TEXT NOT NULL,
|
||||
"id" UUID NOT NULL,
|
||||
"actionId" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"tenantId" UUID NOT NULL,
|
||||
|
||||
@@ -228,8 +242,8 @@ CREATE TABLE "UserOAuth" (
|
||||
"userId" UUID NOT NULL,
|
||||
"provider" TEXT NOT NULL,
|
||||
"providerUserId" TEXT NOT NULL,
|
||||
"accessToken" TEXT NOT NULL,
|
||||
"refreshToken" TEXT,
|
||||
"accessToken" BYTEA NOT NULL,
|
||||
"refreshToken" BYTEA,
|
||||
"expiresAt" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "UserOAuth_pkey" PRIMARY KEY ("id")
|
||||
@@ -376,7 +390,7 @@ CREATE TABLE "WorkflowVersion" (
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_ActionToWorker" (
|
||||
"A" TEXT NOT NULL,
|
||||
"A" UUID NOT NULL,
|
||||
"B" UUID NOT NULL
|
||||
);
|
||||
|
||||
@@ -405,7 +419,13 @@ CREATE TABLE "_WorkflowToWorkflowTag" (
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Action_tenantId_id_key" ON "Action"("tenantId" ASC, "id" ASC);
|
||||
CREATE UNIQUE INDEX "APIToken_id_key" ON "APIToken"("id" ASC);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Action_id_key" ON "Action"("id" ASC);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Action_tenantId_actionId_key" ON "Action"("tenantId" ASC, "actionId" ASC);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Dispatcher_id_key" ON "Dispatcher"("id" ASC);
|
||||
@@ -566,6 +586,9 @@ CREATE UNIQUE INDEX "_WorkflowToWorkflowTag_AB_unique" ON "_WorkflowToWorkflowTa
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_WorkflowToWorkflowTag_B_index" ON "_WorkflowToWorkflowTag"("B" ASC);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "APIToken" ADD CONSTRAINT "APIToken_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Action" ADD CONSTRAINT "Action_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
@@ -603,7 +626,7 @@ ALTER TABLE "JobRunLookupData" ADD CONSTRAINT "JobRunLookupData_tenantId_fkey" F
|
||||
ALTER TABLE "Service" ADD CONSTRAINT "Service_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Step" ADD CONSTRAINT "Step_actionId_tenantId_fkey" FOREIGN KEY ("actionId", "tenantId") REFERENCES "Action"("id", "tenantId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "Step" ADD CONSTRAINT "Step_actionId_tenantId_fkey" FOREIGN KEY ("actionId", "tenantId") REFERENCES "Action"("actionId", "tenantId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Step" ADD CONSTRAINT "Step_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "Job"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
@@ -222,17 +222,19 @@ JOIN
|
||||
-- name: UpsertAction :exec
|
||||
INSERT INTO "Action" (
|
||||
"id",
|
||||
"actionId",
|
||||
"tenantId"
|
||||
)
|
||||
VALUES (
|
||||
gen_random_uuid(),
|
||||
@action::text,
|
||||
@tenantId::uuid
|
||||
)
|
||||
ON CONFLICT ("tenantId", "id") DO UPDATE
|
||||
ON CONFLICT ("tenantId", "actionId") DO UPDATE
|
||||
SET
|
||||
"tenantId" = EXCLUDED."tenantId"
|
||||
WHERE
|
||||
"Action"."tenantId" = @tenantId AND "Action"."id" = @action;
|
||||
"Action"."tenantId" = @tenantId AND "Action"."actionId" = @action::text;
|
||||
|
||||
-- name: UpsertWorkflowTag :exec
|
||||
INSERT INTO "WorkflowTag" (
|
||||
|
||||
@@ -628,17 +628,19 @@ func (q *Queries) ListWorkflowsLatestRuns(ctx context.Context, db DBTX, arg List
|
||||
const upsertAction = `-- name: UpsertAction :exec
|
||||
INSERT INTO "Action" (
|
||||
"id",
|
||||
"actionId",
|
||||
"tenantId"
|
||||
)
|
||||
VALUES (
|
||||
gen_random_uuid(),
|
||||
$1::text,
|
||||
$2::uuid
|
||||
)
|
||||
ON CONFLICT ("tenantId", "id") DO UPDATE
|
||||
ON CONFLICT ("tenantId", "actionId") DO UPDATE
|
||||
SET
|
||||
"tenantId" = EXCLUDED."tenantId"
|
||||
WHERE
|
||||
"Action"."tenantId" = $2 AND "Action"."id" = $1
|
||||
"Action"."tenantId" = $2 AND "Action"."actionId" = $1::text
|
||||
`
|
||||
|
||||
type UpsertActionParams struct {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
)
|
||||
|
||||
type prismaRepository struct {
|
||||
apiToken repository.APITokenRepository
|
||||
event repository.EventRepository
|
||||
tenant repository.TenantRepository
|
||||
tenantInvite repository.TenantInviteRepository
|
||||
@@ -61,6 +62,7 @@ func NewPrismaRepository(client *db.PrismaClient, pool *pgxpool.Pool, fs ...Pris
|
||||
opts.l = &newLogger
|
||||
|
||||
return &prismaRepository{
|
||||
apiToken: NewAPITokenRepository(client, opts.v),
|
||||
event: NewEventRepository(client, pool, opts.v, opts.l),
|
||||
tenant: NewTenantRepository(client, opts.v),
|
||||
tenantInvite: NewTenantInviteRepository(client, opts.v),
|
||||
@@ -77,6 +79,10 @@ func NewPrismaRepository(client *db.PrismaClient, pool *pgxpool.Pool, fs ...Pris
|
||||
}
|
||||
}
|
||||
|
||||
func (r *prismaRepository) APIToken() repository.APITokenRepository {
|
||||
return r.apiToken
|
||||
}
|
||||
|
||||
func (r *prismaRepository) Event() repository.EventRepository {
|
||||
return r.event
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ func (w *workerRepository) ListWorkers(tenantId string, opts *repository.ListWor
|
||||
if opts.Action != nil {
|
||||
queryParams = append(queryParams, db.Worker.Actions.Some(
|
||||
db.Action.TenantID.Equals(tenantId),
|
||||
db.Action.ID.Equals(*opts.Action),
|
||||
db.Action.ActionID.Equals(*opts.Action),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -203,12 +203,12 @@ func (w *workerRepository) CreateNewWorker(tenantId string, opts *repository.Cre
|
||||
if len(opts.Actions) > 0 {
|
||||
for _, action := range opts.Actions {
|
||||
txs = append(txs, w.client.Action.UpsertOne(
|
||||
db.Action.TenantIDID(
|
||||
db.Action.TenantIDActionID(
|
||||
db.Action.TenantID.Equals(tenantId),
|
||||
db.Action.ID.Equals(action),
|
||||
db.Action.ActionID.Equals(action),
|
||||
),
|
||||
).Create(
|
||||
db.Action.ID.Set(action),
|
||||
db.Action.ActionID.Set(action),
|
||||
db.Action.Tenant.Link(
|
||||
db.Tenant.ID.Equals(tenantId),
|
||||
),
|
||||
@@ -221,9 +221,9 @@ func (w *workerRepository) CreateNewWorker(tenantId string, opts *repository.Cre
|
||||
db.Worker.ID.Equals(workerId),
|
||||
).Update(
|
||||
db.Worker.Actions.Link(
|
||||
db.Action.TenantIDID(
|
||||
db.Action.TenantIDActionID(
|
||||
db.Action.TenantID.Equals(tenantId),
|
||||
db.Action.ID.Equals(action),
|
||||
db.Action.ActionID.Equals(action),
|
||||
),
|
||||
),
|
||||
).Tx())
|
||||
@@ -265,12 +265,12 @@ func (w *workerRepository) UpdateWorker(tenantId, workerId string, opts *reposit
|
||||
if len(opts.Actions) > 0 {
|
||||
for _, action := range opts.Actions {
|
||||
txs = append(txs, w.client.Action.UpsertOne(
|
||||
db.Action.TenantIDID(
|
||||
db.Action.TenantIDActionID(
|
||||
db.Action.TenantID.Equals(tenantId),
|
||||
db.Action.ID.Equals(action),
|
||||
db.Action.ActionID.Equals(action),
|
||||
),
|
||||
).Create(
|
||||
db.Action.ID.Set(action),
|
||||
db.Action.ActionID.Set(action),
|
||||
db.Action.Tenant.Link(
|
||||
db.Tenant.ID.Equals(tenantId),
|
||||
),
|
||||
@@ -283,9 +283,9 @@ func (w *workerRepository) UpdateWorker(tenantId, workerId string, opts *reposit
|
||||
db.Worker.ID.Equals(workerId),
|
||||
).Update(
|
||||
db.Worker.Actions.Link(
|
||||
db.Action.TenantIDID(
|
||||
db.Action.TenantIDActionID(
|
||||
db.Action.TenantID.Equals(tenantId),
|
||||
db.Action.ID.Equals(action),
|
||||
db.Action.ActionID.Equals(action),
|
||||
),
|
||||
),
|
||||
).Tx())
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package repository
|
||||
|
||||
type Repository interface {
|
||||
APIToken() APITokenRepository
|
||||
Event() EventRepository
|
||||
Tenant() TenantRepository
|
||||
TenantInvite() TenantInviteRepository
|
||||
|
||||
@@ -22,8 +22,8 @@ type CreateUserOpts struct {
|
||||
type OAuthOpts struct {
|
||||
Provider string `validate:"required,oneof=google"`
|
||||
ProviderUserId string `validate:"required,min=1"`
|
||||
AccessToken string `validate:"required,min=1"`
|
||||
RefreshToken *string // optional
|
||||
AccessToken []byte `validate:"required,min=1"`
|
||||
RefreshToken *[]byte // optional
|
||||
ExpiresAt *time.Time // optional
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,7 @@ type PutWorkflowRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
TenantId string `protobuf:"bytes,1,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"`
|
||||
Opts *CreateWorkflowVersionOpts `protobuf:"bytes,2,opt,name=opts,proto3" json:"opts,omitempty"`
|
||||
Opts *CreateWorkflowVersionOpts `protobuf:"bytes,1,opt,name=opts,proto3" json:"opts,omitempty"`
|
||||
}
|
||||
|
||||
func (x *PutWorkflowRequest) Reset() {
|
||||
@@ -63,13 +62,6 @@ func (*PutWorkflowRequest) Descriptor() ([]byte, []int) {
|
||||
return file_workflows_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *PutWorkflowRequest) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PutWorkflowRequest) GetOpts() *CreateWorkflowVersionOpts {
|
||||
if x != nil {
|
||||
return x.Opts
|
||||
@@ -330,8 +322,6 @@ type ListWorkflowsRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
TenantId string `protobuf:"bytes,1,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ListWorkflowsRequest) Reset() {
|
||||
@@ -366,23 +356,15 @@ func (*ListWorkflowsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_workflows_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *ListWorkflowsRequest) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ScheduleWorkflowRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
TenantId string `protobuf:"bytes,1,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"`
|
||||
WorkflowId string `protobuf:"bytes,2,opt,name=workflow_id,json=workflowId,proto3" json:"workflow_id,omitempty"`
|
||||
Schedules []*timestamppb.Timestamp `protobuf:"bytes,3,rep,name=schedules,proto3" json:"schedules,omitempty"`
|
||||
WorkflowId string `protobuf:"bytes,1,opt,name=workflow_id,json=workflowId,proto3" json:"workflow_id,omitempty"`
|
||||
Schedules []*timestamppb.Timestamp `protobuf:"bytes,2,rep,name=schedules,proto3" json:"schedules,omitempty"`
|
||||
// (optional) the input data for the workflow
|
||||
Input string `protobuf:"bytes,4,opt,name=input,proto3" json:"input,omitempty"`
|
||||
Input string `protobuf:"bytes,3,opt,name=input,proto3" json:"input,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ScheduleWorkflowRequest) Reset() {
|
||||
@@ -417,13 +399,6 @@ func (*ScheduleWorkflowRequest) Descriptor() ([]byte, []int) {
|
||||
return file_workflows_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *ScheduleWorkflowRequest) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ScheduleWorkflowRequest) GetWorkflowId() string {
|
||||
if x != nil {
|
||||
return x.WorkflowId
|
||||
@@ -499,8 +474,7 @@ type ListWorkflowsForEventRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
TenantId string `protobuf:"bytes,1,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"`
|
||||
EventKey string `protobuf:"bytes,2,opt,name=event_key,json=eventKey,proto3" json:"event_key,omitempty"`
|
||||
EventKey string `protobuf:"bytes,1,opt,name=event_key,json=eventKey,proto3" json:"event_key,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ListWorkflowsForEventRequest) Reset() {
|
||||
@@ -535,13 +509,6 @@ func (*ListWorkflowsForEventRequest) Descriptor() ([]byte, []int) {
|
||||
return file_workflows_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *ListWorkflowsForEventRequest) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ListWorkflowsForEventRequest) GetEventKey() string {
|
||||
if x != nil {
|
||||
return x.EventKey
|
||||
@@ -1194,8 +1161,7 @@ type DeleteWorkflowRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
TenantId string `protobuf:"bytes,1,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"`
|
||||
WorkflowId string `protobuf:"bytes,2,opt,name=workflow_id,json=workflowId,proto3" json:"workflow_id,omitempty"`
|
||||
WorkflowId string `protobuf:"bytes,1,opt,name=workflow_id,json=workflowId,proto3" json:"workflow_id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *DeleteWorkflowRequest) Reset() {
|
||||
@@ -1230,13 +1196,6 @@ func (*DeleteWorkflowRequest) Descriptor() ([]byte, []int) {
|
||||
return file_workflows_proto_rawDescGZIP(), []int{15}
|
||||
}
|
||||
|
||||
func (x *DeleteWorkflowRequest) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *DeleteWorkflowRequest) GetWorkflowId() string {
|
||||
if x != nil {
|
||||
return x.WorkflowId
|
||||
@@ -1249,8 +1208,7 @@ type GetWorkflowByNameRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
TenantId string `protobuf:"bytes,1,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetWorkflowByNameRequest) Reset() {
|
||||
@@ -1285,13 +1243,6 @@ func (*GetWorkflowByNameRequest) Descriptor() ([]byte, []int) {
|
||||
return file_workflows_proto_rawDescGZIP(), []int{16}
|
||||
}
|
||||
|
||||
func (x *GetWorkflowByNameRequest) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GetWorkflowByNameRequest) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
@@ -1307,145 +1258,108 @@ var file_workflows_proto_rawDesc = []byte{
|
||||
0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x22, 0x61, 0x0a, 0x12, 0x50, 0x75, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
|
||||
0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x6e, 0x61,
|
||||
0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e,
|
||||
0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x73, 0x52,
|
||||
0x04, 0x6f, 0x70, 0x74, 0x73, 0x22, 0xae, 0x02, 0x0a, 0x19, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||
0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4f,
|
||||
0x74, 0x6f, 0x22, 0x44, 0x0a, 0x12, 0x50, 0x75, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
|
||||
0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6f, 0x70, 0x74, 0x73,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57,
|
||||
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70,
|
||||
0x74, 0x73, 0x52, 0x04, 0x6f, 0x70, 0x74, 0x73, 0x22, 0xae, 0x02, 0x0a, 0x19, 0x43, 0x72, 0x65,
|
||||
0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65,
|
||||
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07,
|
||||
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76,
|
||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f,
|
||||
0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d,
|
||||
0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x23, 0x0a,
|
||||
0x0d, 0x63, 0x72, 0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x18, 0x05,
|
||||
0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x72, 0x6f, 0x6e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65,
|
||||
0x72, 0x73, 0x12, 0x49, 0x0a, 0x12, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f,
|
||||
0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 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, 0x11, 0x73, 0x63, 0x68, 0x65,
|
||||
0x64, 0x75, 0x6c, 0x65, 0x64, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a,
|
||||
0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x43, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4a, 0x6f, 0x62, 0x4f,
|
||||
0x70, 0x74, 0x73, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x22, 0x96, 0x01, 0x0a, 0x15, 0x43, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4a, 0x6f, 0x62, 0x4f,
|
||||
0x70, 0x74, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
|
||||
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65,
|
||||
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x72, 0x69,
|
||||
0x67, 0x67, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x76, 0x65,
|
||||
0x6e, 0x74, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72,
|
||||
0x6f, 0x6e, 0x5f, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28,
|
||||
0x09, 0x52, 0x0c, 0x63, 0x72, 0x6f, 0x6e, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x12,
|
||||
0x49, 0x0a, 0x12, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x64, 0x5f, 0x74, 0x72, 0x69,
|
||||
0x67, 0x67, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 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, 0x11, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
|
||||
0x65, 0x64, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x04, 0x6a, 0x6f,
|
||||
0x62, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4a, 0x6f, 0x62, 0x4f, 0x70, 0x74, 0x73,
|
||||
0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x22, 0x96, 0x01, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4a, 0x6f, 0x62, 0x4f, 0x70, 0x74, 0x73,
|
||||
0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
|
||||
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75,
|
||||
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d,
|
||||
0x65, 0x6f, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65,
|
||||
0x6f, 0x75, 0x74, 0x12, 0x2d, 0x0a, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x17, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66,
|
||||
0x6c, 0x6f, 0x77, 0x53, 0x74, 0x65, 0x70, 0x4f, 0x70, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x65,
|
||||
0x70, 0x73, 0x22, 0x9d, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72,
|
||||
0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x74, 0x65, 0x70, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x1f, 0x0a,
|
||||
0x0b, 0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x16,
|
||||
0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75,
|
||||
0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
|
||||
0x12, 0x2d, 0x0a, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x17, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
|
||||
0x53, 0x74, 0x65, 0x70, 0x4f, 0x70, 0x74, 0x73, 0x52, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x22,
|
||||
0x9d, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x6f, 0x77, 0x53, 0x74, 0x65, 0x70, 0x4f, 0x70, 0x74, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65,
|
||||
0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0a, 0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x16, 0x0a,
|
||||
0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x69,
|
||||
0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73,
|
||||
0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22,
|
||||
0x33, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x6e, 0x61, 0x6e,
|
||||
0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61,
|
||||
0x6e, 0x74, 0x49, 0x64, 0x22, 0xa7, 0x01, 0x0a, 0x17, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
|
||||
0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a,
|
||||
0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x12, 0x38,
|
||||
0x0a, 0x09, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
|
||||
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73,
|
||||
0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75,
|
||||
0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x40,
|
||||
0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x66,
|
||||
0x6c, 0x6f, 0x77, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x57, 0x6f, 0x72,
|
||||
0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73,
|
||||
0x22, 0x58, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
|
||||
0x73, 0x46, 0x6f, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a,
|
||||
0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x22, 0xaf, 0x02, 0x0a, 0x08, 0x57,
|
||||
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
|
||||
0x12, 0x16, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65,
|
||||
0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e,
|
||||
0x74, 0x73, 0x22, 0x16, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x6f, 0x77, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8a, 0x01, 0x0a, 0x17, 0x53,
|
||||
0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72,
|
||||
0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x09, 0x73, 0x63, 0x68, 0x65, 0x64,
|
||||
0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
|
||||
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
|
||||
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
|
||||
0x73, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x22, 0x40, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x57,
|
||||
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x27, 0x0a, 0x09, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x18, 0x01, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x09,
|
||||
0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x22, 0x3b, 0x0a, 0x1c, 0x4c, 0x69, 0x73,
|
||||
0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x46, 0x6f, 0x72, 0x45, 0x76, 0x65,
|
||||
0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x76, 0x65,
|
||||
0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x76,
|
||||
0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x22, 0xaf, 0x02, 0x0a, 0x08, 0x57, 0x6f, 0x72, 0x6b, 0x66,
|
||||
0x6c, 0x6f, 0x77, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61,
|
||||
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
|
||||
0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39,
|
||||
0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09,
|
||||
0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x6e,
|
||||
0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65,
|
||||
0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x64, 0x65,
|
||||
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||
0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x64,
|
||||
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x08, 0x76, 0x65,
|
||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x57,
|
||||
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08,
|
||||
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xb1, 0x02, 0x0a, 0x0f, 0x57, 0x6f, 0x72,
|
||||
0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02,
|
||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0a,
|
||||
0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74,
|
||||
0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
|
||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64,
|
||||
0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
||||
0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1b, 0x0a,
|
||||
0x09, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3e,
|
||||
0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c,
|
||||
0x0a, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x10, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x52, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xb1, 0x02, 0x0a,
|
||||
0x0f, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
|
||||
0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
|
||||
0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75,
|
||||
0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||
0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||
0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72,
|
||||
0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x08, 0x74, 0x72, 0x69, 0x67, 0x67,
|
||||
0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x57, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x52, 0x08, 0x74, 0x72,
|
||||
0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x18, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x09,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x04, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73,
|
||||
0x22, 0xc6, 0x02, 0x0a, 0x10, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x72, 0x69,
|
||||
0x67, 0x67, 0x65, 0x72, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64,
|
||||
0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
|
||||
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74,
|
||||
0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
|
||||
0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x77,
|
||||
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x74,
|
||||
0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66,
|
||||
0x6c, 0x6f, 0x77, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52,
|
||||
0x65, 0x66, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2d, 0x0a, 0x05, 0x63, 0x72,
|
||||
0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x57, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x43, 0x72, 0x6f, 0x6e, 0x52,
|
||||
0x65, 0x66, 0x52, 0x05, 0x63, 0x72, 0x6f, 0x6e, 0x73, 0x22, 0x53, 0x0a, 0x17, 0x57, 0x6f, 0x72,
|
||||
0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x52, 0x65, 0x66, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49,
|
||||
0x64, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x49,
|
||||
0x0a, 0x16, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65,
|
||||
0x72, 0x43, 0x72, 0x6f, 0x6e, 0x52, 0x65, 0x66, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x65,
|
||||
0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x72,
|
||||
0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x22, 0x81, 0x03, 0x0a, 0x03, 0x4a, 0x6f,
|
||||
0x62, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
|
||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
|
||||
0x41, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05,
|
||||
0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6f, 0x72, 0x64,
|
||||
0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
|
||||
0x77, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x08, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x18,
|
||||
0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
|
||||
0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x73, 0x52, 0x08, 0x74, 0x72, 0x69, 0x67, 0x67, 0x65,
|
||||
0x72, 0x73, 0x12, 0x18, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x04, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x22, 0xc6, 0x02, 0x0a,
|
||||
0x10, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72,
|
||||
0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
|
||||
0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 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,
|
||||
@@ -1453,86 +1367,113 @@ var file_workflows_proto_rawDesc = []byte{
|
||||
0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70,
|
||||
0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x6e, 0x61, 0x6e,
|
||||
0x74, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61,
|
||||
0x6e, 0x74, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
|
||||
0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63,
|
||||
0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e,
|
||||
0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x66,
|
||||
0x6c, 0x6f, 0x77, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65,
|
||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x6e, 0x61, 0x6e,
|
||||
0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61,
|
||||
0x6e, 0x74, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x07,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54,
|
||||
0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x66, 0x52, 0x06,
|
||||
0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2d, 0x0a, 0x05, 0x63, 0x72, 0x6f, 0x6e, 0x73, 0x18,
|
||||
0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
|
||||
0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x43, 0x72, 0x6f, 0x6e, 0x52, 0x65, 0x66, 0x52, 0x05,
|
||||
0x63, 0x72, 0x6f, 0x6e, 0x73, 0x22, 0x53, 0x0a, 0x17, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
|
||||
0x77, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x66,
|
||||
0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1b, 0x0a,
|
||||
0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x49, 0x0a, 0x16, 0x57, 0x6f,
|
||||
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x43, 0x72, 0x6f,
|
||||
0x6e, 0x52, 0x65, 0x66, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49,
|
||||
0x64, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x04, 0x63, 0x72, 0x6f, 0x6e, 0x22, 0x81, 0x03, 0x0a, 0x03, 0x4a, 0x6f, 0x62, 0x12, 0x0e, 0x0a,
|
||||
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a,
|
||||
0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63,
|
||||
0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61,
|
||||
0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
|
||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65,
|
||||
0x64, 0x41, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64,
|
||||
0x12, 0x2e, 0x0a, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x76, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x77,
|
||||
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64,
|
||||
0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
||||
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69,
|
||||
0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x18, 0x09, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x05, 0x2e, 0x53, 0x74, 0x65, 0x70, 0x52, 0x05, 0x73, 0x74, 0x65, 0x70,
|
||||
0x73, 0x12, 0x36, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x0a, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x85, 0x03, 0x0a, 0x04, 0x53, 0x74,
|
||||
0x65, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
|
||||
0x69, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
||||
0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a,
|
||||
0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75,
|
||||
0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3d, 0x0a, 0x0b, 0x72, 0x65, 0x61, 0x64,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||
0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x73,
|
||||
0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x05, 0x73, 0x74, 0x65, 0x70,
|
||||
0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x05, 0x2e, 0x53, 0x74, 0x65, 0x70, 0x52, 0x05,
|
||||
0x73, 0x74, 0x65, 0x70, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
|
||||
0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56,
|
||||
0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x85, 0x03,
|
||||
0x0a, 0x04, 0x53, 0x74, 0x65, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||
0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
|
||||
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
|
||||
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41,
|
||||
0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
|
||||
0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3d, 0x0a, 0x0b,
|
||||
0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52,
|
||||
0x0a, 0x72, 0x65, 0x61, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x74,
|
||||
0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12,
|
||||
0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f,
|
||||
0x75, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e,
|
||||
0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12,
|
||||
0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09,
|
||||
0x52, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x69,
|
||||
0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x68, 0x69,
|
||||
0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x55, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57,
|
||||
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b,
|
||||
0x0a, 0x09, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x77,
|
||||
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x22, 0x4b, 0x0a, 0x18,
|
||||
0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61, 0x6d,
|
||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x6e, 0x61,
|
||||
0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e,
|
||||
0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0x87, 0x03, 0x0a, 0x0f, 0x57, 0x6f,
|
||||
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a,
|
||||
0x0d, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x12, 0x15,
|
||||
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a,
|
||||
0x0b, 0x50, 0x75, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x13, 0x2e, 0x50,
|
||||
0x75, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x10, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x10, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x57,
|
||||
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75,
|
||||
0x6c, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x10, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65, 0x72, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x2e, 0x47, 0x65, 0x74, 0x57, 0x6f,
|
||||
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x4e,
|
||||
0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x46,
|
||||
0x6f, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f,
|
||||
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x46, 0x6f, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72,
|
||||
0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33,
|
||||
0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
|
||||
0x12, 0x16, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
|
||||
0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66,
|
||||
0x6c, 0x6f, 0x77, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x61,
|
||||
0x74, 0x63, 0x68, 0x65, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x72, 0x65, 0x61,
|
||||
0x64, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x6e, 0x61, 0x6e,
|
||||
0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61,
|
||||
0x6e, 0x74, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x07,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x09,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70,
|
||||
0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61,
|
||||
0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65,
|
||||
0x6e, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65,
|
||||
0x6e, 0x22, 0x38, 0x0a, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66,
|
||||
0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x6f,
|
||||
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x22, 0x2e, 0x0a, 0x18, 0x47,
|
||||
0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0x87, 0x03, 0x0a, 0x0f,
|
||||
0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0x3e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73,
|
||||
0x12, 0x15, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f,
|
||||
0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x34, 0x0a, 0x0b, 0x50, 0x75, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x13,
|
||||
0x2e, 0x50, 0x75, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65,
|
||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x10, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
|
||||
0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x2e, 0x53, 0x63, 0x68, 0x65,
|
||||
0x64, 0x75, 0x6c, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x56, 0x65,
|
||||
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b,
|
||||
0x66, 0x6c, 0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x2e, 0x47, 0x65, 0x74,
|
||||
0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
|
||||
0x12, 0x4e, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
|
||||
0x73, 0x46, 0x6f, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x46, 0x6f, 0x72, 0x45, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x57,
|
||||
0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x33, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c,
|
||||
0x6f, 0x77, 0x12, 0x16, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x57, 0x6f, 0x72, 0x6b, 0x66,
|
||||
0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x09, 0x2e, 0x57, 0x6f, 0x72,
|
||||
0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, 0x2f,
|
||||
0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
|
||||
0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -22,8 +22,10 @@ import (
|
||||
)
|
||||
|
||||
func (a *AdminServiceImpl) GetWorkflowByName(ctx context.Context, req *contracts.GetWorkflowByNameRequest) (*contracts.Workflow, error) {
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
workflow, err := a.repo.Workflow().GetWorkflowByName(
|
||||
req.TenantId,
|
||||
tenant.ID,
|
||||
req.Name,
|
||||
)
|
||||
|
||||
@@ -44,7 +46,7 @@ func (a *AdminServiceImpl) GetWorkflowByName(ctx context.Context, req *contracts
|
||||
}
|
||||
|
||||
func (a *AdminServiceImpl) PutWorkflow(ctx context.Context, req *contracts.PutWorkflowRequest) (*contracts.WorkflowVersion, error) {
|
||||
// TODO: authorize request
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
createOpts, err := getCreateWorkflowOpts(req)
|
||||
|
||||
@@ -57,7 +59,7 @@ func (a *AdminServiceImpl) PutWorkflow(ctx context.Context, req *contracts.PutWo
|
||||
var oldWorkflowVersion *db.WorkflowVersionModel
|
||||
|
||||
currWorkflow, err := a.repo.Workflow().GetWorkflowByName(
|
||||
req.TenantId,
|
||||
tenant.ID,
|
||||
req.Opts.Name,
|
||||
)
|
||||
|
||||
@@ -68,7 +70,7 @@ func (a *AdminServiceImpl) PutWorkflow(ctx context.Context, req *contracts.PutWo
|
||||
|
||||
// workflow does not exist, create it
|
||||
workflowVersion, err = a.repo.Workflow().CreateNewWorkflow(
|
||||
req.TenantId,
|
||||
tenant.ID,
|
||||
createOpts,
|
||||
)
|
||||
|
||||
@@ -80,7 +82,7 @@ func (a *AdminServiceImpl) PutWorkflow(ctx context.Context, req *contracts.PutWo
|
||||
|
||||
// workflow exists, create a new version
|
||||
workflowVersion, err = a.repo.Workflow().CreateWorkflowVersion(
|
||||
req.TenantId,
|
||||
tenant.ID,
|
||||
createOpts,
|
||||
)
|
||||
|
||||
@@ -295,7 +297,7 @@ func (a *AdminServiceImpl) PutWorkflow(ctx context.Context, req *contracts.PutWo
|
||||
}
|
||||
|
||||
func (a *AdminServiceImpl) ScheduleWorkflow(ctx context.Context, req *contracts.ScheduleWorkflowRequest) (*contracts.WorkflowVersion, error) {
|
||||
// TODO: authorize request
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
currWorkflow, err := a.repo.Workflow().GetWorkflowById(
|
||||
req.WorkflowId,
|
||||
@@ -336,7 +338,7 @@ func (a *AdminServiceImpl) ScheduleWorkflow(ctx context.Context, req *contracts.
|
||||
}
|
||||
|
||||
schedules, err := a.repo.Workflow().CreateSchedules(
|
||||
req.TenantId,
|
||||
tenant.ID,
|
||||
workflowVersion.ID,
|
||||
&repository.CreateWorkflowSchedulesOpts{
|
||||
ScheduledTriggers: dbSchedules,
|
||||
@@ -416,8 +418,10 @@ func (a *AdminServiceImpl) ScheduleWorkflow(ctx context.Context, req *contracts.
|
||||
}
|
||||
|
||||
func (a *AdminServiceImpl) DeleteWorkflow(ctx context.Context, req *contracts.DeleteWorkflowRequest) (*contracts.Workflow, error) {
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
workflow, err := a.repo.Workflow().DeleteWorkflow(
|
||||
req.TenantId,
|
||||
tenant.ID,
|
||||
req.WorkflowId,
|
||||
)
|
||||
|
||||
@@ -434,8 +438,10 @@ func (a *AdminServiceImpl) ListWorkflows(
|
||||
ctx context.Context,
|
||||
req *contracts.ListWorkflowsRequest,
|
||||
) (*contracts.ListWorkflowsResponse, error) {
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
listResp, err := a.repo.Workflow().ListWorkflows(
|
||||
req.TenantId,
|
||||
tenant.ID,
|
||||
&repository.ListWorkflowsOpts{},
|
||||
)
|
||||
|
||||
@@ -458,8 +464,10 @@ func (a *AdminServiceImpl) ListWorkflowsForEvent(
|
||||
ctx context.Context,
|
||||
req *contracts.ListWorkflowsForEventRequest,
|
||||
) (*contracts.ListWorkflowsResponse, error) {
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
listResp, err := a.repo.Workflow().ListWorkflows(
|
||||
req.TenantId,
|
||||
tenant.ID,
|
||||
&repository.ListWorkflowsOpts{
|
||||
EventKey: &req.EventKey,
|
||||
},
|
||||
|
||||
@@ -124,14 +124,12 @@ type WorkerRegisterRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// the tenant id
|
||||
TenantId string `protobuf:"bytes,1,opt,name=tenantId,proto3" json:"tenantId,omitempty"`
|
||||
// the name of the worker
|
||||
WorkerName string `protobuf:"bytes,2,opt,name=workerName,proto3" json:"workerName,omitempty"`
|
||||
WorkerName string `protobuf:"bytes,1,opt,name=workerName,proto3" json:"workerName,omitempty"`
|
||||
// a list of actions that this worker can run
|
||||
Actions []string `protobuf:"bytes,3,rep,name=actions,proto3" json:"actions,omitempty"`
|
||||
Actions []string `protobuf:"bytes,2,rep,name=actions,proto3" json:"actions,omitempty"`
|
||||
// (optional) the services for this worker
|
||||
Services []string `protobuf:"bytes,4,rep,name=services,proto3" json:"services,omitempty"`
|
||||
Services []string `protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty"`
|
||||
}
|
||||
|
||||
func (x *WorkerRegisterRequest) Reset() {
|
||||
@@ -166,13 +164,6 @@ func (*WorkerRegisterRequest) Descriptor() ([]byte, []int) {
|
||||
return file_dispatcher_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *WorkerRegisterRequest) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *WorkerRegisterRequest) GetWorkerName() string {
|
||||
if x != nil {
|
||||
return x.WorkerName
|
||||
@@ -385,10 +376,8 @@ type WorkerListenRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// the tenant id
|
||||
TenantId string `protobuf:"bytes,1,opt,name=tenantId,proto3" json:"tenantId,omitempty"`
|
||||
// the id of the worker
|
||||
WorkerId string `protobuf:"bytes,2,opt,name=workerId,proto3" json:"workerId,omitempty"`
|
||||
WorkerId string `protobuf:"bytes,1,opt,name=workerId,proto3" json:"workerId,omitempty"`
|
||||
}
|
||||
|
||||
func (x *WorkerListenRequest) Reset() {
|
||||
@@ -423,13 +412,6 @@ func (*WorkerListenRequest) Descriptor() ([]byte, []int) {
|
||||
return file_dispatcher_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *WorkerListenRequest) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *WorkerListenRequest) GetWorkerId() string {
|
||||
if x != nil {
|
||||
return x.WorkerId
|
||||
@@ -442,10 +424,8 @@ type WorkerUnsubscribeRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// the tenant id to unsubscribe from
|
||||
TenantId string `protobuf:"bytes,1,opt,name=tenantId,proto3" json:"tenantId,omitempty"`
|
||||
// the id of the worker
|
||||
WorkerId string `protobuf:"bytes,2,opt,name=workerId,proto3" json:"workerId,omitempty"`
|
||||
WorkerId string `protobuf:"bytes,1,opt,name=workerId,proto3" json:"workerId,omitempty"`
|
||||
}
|
||||
|
||||
func (x *WorkerUnsubscribeRequest) Reset() {
|
||||
@@ -480,13 +460,6 @@ func (*WorkerUnsubscribeRequest) Descriptor() ([]byte, []int) {
|
||||
return file_dispatcher_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *WorkerUnsubscribeRequest) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *WorkerUnsubscribeRequest) GetWorkerId() string {
|
||||
if x != nil {
|
||||
return x.WorkerId
|
||||
@@ -556,25 +529,23 @@ type ActionEvent struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// the tenant id
|
||||
TenantId string `protobuf:"bytes,1,opt,name=tenantId,proto3" json:"tenantId,omitempty"`
|
||||
// the id of the worker
|
||||
WorkerId string `protobuf:"bytes,2,opt,name=workerId,proto3" json:"workerId,omitempty"`
|
||||
WorkerId string `protobuf:"bytes,1,opt,name=workerId,proto3" json:"workerId,omitempty"`
|
||||
// the id of the job
|
||||
JobId string `protobuf:"bytes,3,opt,name=jobId,proto3" json:"jobId,omitempty"`
|
||||
JobId string `protobuf:"bytes,2,opt,name=jobId,proto3" json:"jobId,omitempty"`
|
||||
// the job run id
|
||||
JobRunId string `protobuf:"bytes,4,opt,name=jobRunId,proto3" json:"jobRunId,omitempty"`
|
||||
JobRunId string `protobuf:"bytes,3,opt,name=jobRunId,proto3" json:"jobRunId,omitempty"`
|
||||
// the id of the step
|
||||
StepId string `protobuf:"bytes,5,opt,name=stepId,proto3" json:"stepId,omitempty"`
|
||||
StepId string `protobuf:"bytes,4,opt,name=stepId,proto3" json:"stepId,omitempty"`
|
||||
// the step run id
|
||||
StepRunId string `protobuf:"bytes,6,opt,name=stepRunId,proto3" json:"stepRunId,omitempty"`
|
||||
StepRunId string `protobuf:"bytes,5,opt,name=stepRunId,proto3" json:"stepRunId,omitempty"`
|
||||
// the action id
|
||||
ActionId string `protobuf:"bytes,7,opt,name=actionId,proto3" json:"actionId,omitempty"`
|
||||
EventTimestamp *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=eventTimestamp,proto3" json:"eventTimestamp,omitempty"`
|
||||
ActionId string `protobuf:"bytes,6,opt,name=actionId,proto3" json:"actionId,omitempty"`
|
||||
EventTimestamp *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=eventTimestamp,proto3" json:"eventTimestamp,omitempty"`
|
||||
// the step event type
|
||||
EventType ActionEventType `protobuf:"varint,9,opt,name=eventType,proto3,enum=ActionEventType" json:"eventType,omitempty"`
|
||||
EventType ActionEventType `protobuf:"varint,8,opt,name=eventType,proto3,enum=ActionEventType" json:"eventType,omitempty"`
|
||||
// the event payload
|
||||
EventPayload string `protobuf:"bytes,10,opt,name=eventPayload,proto3" json:"eventPayload,omitempty"`
|
||||
EventPayload string `protobuf:"bytes,9,opt,name=eventPayload,proto3" json:"eventPayload,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ActionEvent) Reset() {
|
||||
@@ -609,13 +580,6 @@ func (*ActionEvent) Descriptor() ([]byte, []int) {
|
||||
return file_dispatcher_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *ActionEvent) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ActionEvent) GetWorkerId() string {
|
||||
if x != nil {
|
||||
return x.WorkerId
|
||||
@@ -742,117 +706,109 @@ var file_dispatcher_proto_rawDesc = []byte{
|
||||
0x0a, 0x10, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x22, 0x89, 0x01, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65,
|
||||
0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a,
|
||||
0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x77, 0x6f, 0x72,
|
||||
0x6b, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77,
|
||||
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18,
|
||||
0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22,
|
||||
0x70, 0x0a, 0x16, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
|
||||
0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6e,
|
||||
0x61, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e,
|
||||
0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49,
|
||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49,
|
||||
0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4e, 0x61, 0x6d,
|
||||
0x65, 0x22, 0x9d, 0x02, 0x0a, 0x0e, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x41, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d,
|
||||
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e, 0x61, 0x6d, 0x65,
|
||||
0x12, 0x1a, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x08, 0x6a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x73, 0x74, 0x65, 0x70, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74,
|
||||
0x65, 0x70, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x65, 0x70, 0x52, 0x75, 0x6e, 0x49,
|
||||
0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x65, 0x70, 0x52, 0x75, 0x6e,
|
||||
0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x07,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x2b,
|
||||
0x0a, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01,
|
||||
0x28, 0x0e, 0x32, 0x0b, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52,
|
||||
0x0a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x61,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x09, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61,
|
||||
0x64, 0x22, 0x4d, 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x65,
|
||||
0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6e, 0x61,
|
||||
0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61,
|
||||
0x6e, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64,
|
||||
0x22, 0x52, 0x0a, 0x18, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73,
|
||||
0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x6f, 0x74, 0x6f, 0x22, 0x6d, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x67,
|
||||
0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x0a,
|
||||
0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07,
|
||||
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x61,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x22, 0x70, 0x0a, 0x16, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69,
|
||||
0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x65, 0x72, 0x49, 0x64, 0x22, 0x53, 0x0a, 0x19, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x55, 0x6e,
|
||||
0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a,
|
||||
0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x22, 0xe1, 0x02, 0x0a, 0x0b, 0x41, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6e,
|
||||
0x61, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e,
|
||||
0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49,
|
||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49,
|
||||
0x64, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x52, 0x75,
|
||||
0x6e, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6a, 0x6f, 0x62, 0x52, 0x75,
|
||||
0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x65, 0x70, 0x49, 0x64, 0x18, 0x05, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x65, 0x70, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73,
|
||||
0x74, 0x65, 0x70, 0x52, 0x75, 0x6e, 0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
|
||||
0x73, 0x74, 0x65, 0x70, 0x52, 0x75, 0x6e, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x49, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x42, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69,
|
||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74,
|
||||
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, 0x0a, 0x09, 0x65, 0x76, 0x65,
|
||||
0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x41,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09,
|
||||
0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x76, 0x65,
|
||||
0x6e, 0x74, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0c, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x4d, 0x0a,
|
||||
0x13, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64,
|
||||
0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x2a, 0x35, 0x0a, 0x0a,
|
||||
0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x54,
|
||||
0x41, 0x52, 0x54, 0x5f, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x52, 0x55, 0x4e, 0x10, 0x00, 0x12, 0x13,
|
||||
0x0a, 0x0f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x5f, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x52, 0x55,
|
||||
0x4e, 0x10, 0x01, 0x2a, 0x86, 0x01, 0x0a, 0x0f, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76,
|
||||
0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x54, 0x45, 0x50, 0x5f,
|
||||
0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f,
|
||||
0x57, 0x4e, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45,
|
||||
0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10,
|
||||
0x01, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f,
|
||||
0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02,
|
||||
0x12, 0x1a, 0x0a, 0x16, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54,
|
||||
0x59, 0x50, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x32, 0x81, 0x02, 0x0a,
|
||||
0x0a, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x08, 0x52,
|
||||
0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x16, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72,
|
||||
0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x17, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x06, 0x4c, 0x69,
|
||||
0x73, 0x74, 0x65, 0x6e, 0x12, 0x14, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x69, 0x73,
|
||||
0x74, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x41, 0x73, 0x73,
|
||||
0x69, 0x67, 0x6e, 0x65, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x30, 0x01, 0x12,
|
||||
0x37, 0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65,
|
||||
0x6e, 0x74, 0x12, 0x0c, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74,
|
||||
0x1a, 0x14, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0b, 0x55, 0x6e, 0x73, 0x75,
|
||||
0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x19, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72,
|
||||
0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x55, 0x6e, 0x73, 0x75, 0x62,
|
||||
0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||
0x42, 0x47, 0x5a, 0x45, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68,
|
||||
0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68,
|
||||
0x65, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2f,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
0x65, 0x72, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4e, 0x61,
|
||||
0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72,
|
||||
0x4e, 0x61, 0x6d, 0x65, 0x22, 0x9d, 0x02, 0x0a, 0x0e, 0x41, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65,
|
||||
0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e,
|
||||
0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e,
|
||||
0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x6a, 0x6f, 0x62,
|
||||
0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6a, 0x6f, 0x62, 0x4e,
|
||||
0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x49, 0x64, 0x18,
|
||||
0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6a, 0x6f, 0x62, 0x52, 0x75, 0x6e, 0x49, 0x64, 0x12,
|
||||
0x16, 0x0a, 0x06, 0x73, 0x74, 0x65, 0x70, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x06, 0x73, 0x74, 0x65, 0x70, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x65, 0x70, 0x52,
|
||||
0x75, 0x6e, 0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x65, 0x70,
|
||||
0x52, 0x75, 0x6e, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49,
|
||||
0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49,
|
||||
0x64, 0x12, 0x2b, 0x0a, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x18,
|
||||
0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0b, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79,
|
||||
0x70, 0x65, 0x52, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24,
|
||||
0x0a, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18,
|
||||
0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79,
|
||||
0x6c, 0x6f, 0x61, 0x64, 0x22, 0x31, 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x69,
|
||||
0x73, 0x74, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x77,
|
||||
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77,
|
||||
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x22, 0x36, 0x0a, 0x18, 0x57, 0x6f, 0x72, 0x6b, 0x65,
|
||||
0x72, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x22,
|
||||
0x53, 0x0a, 0x19, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73, 0x63,
|
||||
0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b,
|
||||
0x65, 0x72, 0x49, 0x64, 0x22, 0xc5, 0x02, 0x0a, 0x0b, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45,
|
||||
0x76, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x6a, 0x6f, 0x62, 0x52, 0x75, 0x6e,
|
||||
0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6a, 0x6f, 0x62, 0x52, 0x75, 0x6e,
|
||||
0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x65, 0x70, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x65, 0x70, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74,
|
||||
0x65, 0x70, 0x52, 0x75, 0x6e, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73,
|
||||
0x74, 0x65, 0x70, 0x52, 0x75, 0x6e, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x49, 0x64, 0x12, 0x42, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d,
|
||||
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
|
||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2e, 0x0a, 0x09, 0x65, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x41, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x65,
|
||||
0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
|
||||
0x65, 0x76, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x4d, 0x0a, 0x13,
|
||||
0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12,
|
||||
0x1a, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x49, 0x64, 0x2a, 0x35, 0x0a, 0x0a, 0x41,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x54, 0x41,
|
||||
0x52, 0x54, 0x5f, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x52, 0x55, 0x4e, 0x10, 0x00, 0x12, 0x13, 0x0a,
|
||||
0x0f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x5f, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x52, 0x55, 0x4e,
|
||||
0x10, 0x01, 0x2a, 0x86, 0x01, 0x0a, 0x0f, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65,
|
||||
0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45,
|
||||
0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57,
|
||||
0x4e, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45, 0x4e,
|
||||
0x54, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x45, 0x44, 0x10, 0x01,
|
||||
0x12, 0x1d, 0x0a, 0x19, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54,
|
||||
0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12,
|
||||
0x1a, 0x0a, 0x16, 0x53, 0x54, 0x45, 0x50, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x54, 0x59,
|
||||
0x50, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x32, 0x81, 0x02, 0x0a, 0x0a,
|
||||
0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x08, 0x52, 0x65,
|
||||
0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x16, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52,
|
||||
0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17,
|
||||
0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x06, 0x4c, 0x69, 0x73,
|
||||
0x74, 0x65, 0x6e, 0x12, 0x14, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x41, 0x73, 0x73, 0x69,
|
||||
0x67, 0x6e, 0x65, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x30, 0x01, 0x12, 0x37,
|
||||
0x0a, 0x0f, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x12, 0x0c, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a,
|
||||
0x14, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x0b, 0x55, 0x6e, 0x73, 0x75, 0x62,
|
||||
0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x19, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x55,
|
||||
0x6e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x1a, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x55, 0x6e, 0x73, 0x75, 0x62, 0x73,
|
||||
0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42,
|
||||
0x47, 0x5a, 0x45, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61,
|
||||
0x74, 0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65,
|
||||
0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2f, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -90,7 +90,7 @@ func (worker *subscribedWorker) CancelStepRun(
|
||||
}
|
||||
|
||||
func (s *DispatcherImpl) Register(ctx context.Context, request *contracts.WorkerRegisterRequest) (*contracts.WorkerRegisterResponse, error) {
|
||||
// TODO: auth checks to make sure the worker is allowed to register for this tenant
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
s.l.Debug().Msgf("Received register request from ID %s with actions %v", request.WorkerName, request.Actions)
|
||||
|
||||
@@ -101,7 +101,7 @@ func (s *DispatcherImpl) Register(ctx context.Context, request *contracts.Worker
|
||||
}
|
||||
|
||||
// create a worker in the database
|
||||
worker, err := s.repo.Worker().CreateNewWorker(request.TenantId, &repository.CreateWorkerOpts{
|
||||
worker, err := s.repo.Worker().CreateNewWorker(tenant.ID, &repository.CreateWorkerOpts{
|
||||
DispatcherId: s.dispatcherId,
|
||||
Name: request.WorkerName,
|
||||
Actions: request.Actions,
|
||||
@@ -109,7 +109,7 @@ func (s *DispatcherImpl) Register(ctx context.Context, request *contracts.Worker
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
s.l.Error().Err(err).Msgf("could not create worker for tenant %s", request.TenantId)
|
||||
s.l.Error().Err(err).Msgf("could not create worker for tenant %s", tenant.ID)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -125,6 +125,8 @@ func (s *DispatcherImpl) Register(ctx context.Context, request *contracts.Worker
|
||||
|
||||
// Subscribe handles a subscribe request from a client
|
||||
func (s *DispatcherImpl) Listen(request *contracts.WorkerListenRequest, stream contracts.Dispatcher_ListenServer) error {
|
||||
tenant := stream.Context().Value("tenant").(*db.TenantModel)
|
||||
|
||||
s.l.Debug().Msgf("Received subscribe request from ID: %s", request.WorkerId)
|
||||
|
||||
worker, err := s.repo.Worker().GetWorkerById(request.WorkerId)
|
||||
@@ -136,7 +138,7 @@ func (s *DispatcherImpl) Listen(request *contracts.WorkerListenRequest, stream c
|
||||
|
||||
// check the worker's dispatcher against the current dispatcher. if they don't match, then update the worker
|
||||
if worker.DispatcherID != s.dispatcherId {
|
||||
_, err = s.repo.Worker().UpdateWorker(request.TenantId, request.WorkerId, &repository.UpdateWorkerOpts{
|
||||
_, err = s.repo.Worker().UpdateWorker(tenant.ID, request.WorkerId, &repository.UpdateWorkerOpts{
|
||||
DispatcherId: &s.dispatcherId,
|
||||
})
|
||||
|
||||
@@ -155,7 +157,7 @@ func (s *DispatcherImpl) Listen(request *contracts.WorkerListenRequest, stream c
|
||||
|
||||
inactive := db.WorkerStatusInactive
|
||||
|
||||
_, err := s.repo.Worker().UpdateWorker(request.TenantId, request.WorkerId, &repository.UpdateWorkerOpts{
|
||||
_, err := s.repo.Worker().UpdateWorker(tenant.ID, request.WorkerId, &repository.UpdateWorkerOpts{
|
||||
Status: &inactive,
|
||||
})
|
||||
|
||||
@@ -183,7 +185,7 @@ func (s *DispatcherImpl) Listen(request *contracts.WorkerListenRequest, stream c
|
||||
if now := time.Now().UTC(); lastHeartbeat.Add(5 * time.Second).Before(now) {
|
||||
s.l.Debug().Msgf("updating worker %s heartbeat", request.WorkerId)
|
||||
|
||||
_, err := s.repo.Worker().UpdateWorker(request.TenantId, request.WorkerId, &repository.UpdateWorkerOpts{
|
||||
_, err := s.repo.Worker().UpdateWorker(tenant.ID, request.WorkerId, &repository.UpdateWorkerOpts{
|
||||
LastHeartbeatAt: &now,
|
||||
})
|
||||
|
||||
@@ -227,23 +229,26 @@ func (s *DispatcherImpl) SendActionEvent(ctx context.Context, request *contracts
|
||||
}
|
||||
|
||||
func (s *DispatcherImpl) Unsubscribe(ctx context.Context, request *contracts.WorkerUnsubscribeRequest) (*contracts.WorkerUnsubscribeResponse, error) {
|
||||
// TODO: auth checks to make sure the worker is allowed to unsubscribe for this tenant
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
// no matter what, remove the worker from the connection pool
|
||||
defer s.workers.Delete(request.WorkerId)
|
||||
|
||||
err := s.repo.Worker().DeleteWorker(request.TenantId, request.WorkerId)
|
||||
err := s.repo.Worker().DeleteWorker(tenant.ID, request.WorkerId)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &contracts.WorkerUnsubscribeResponse{
|
||||
TenantId: request.TenantId,
|
||||
TenantId: tenant.ID,
|
||||
WorkerId: request.WorkerId,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *DispatcherImpl) handleStepRunStarted(ctx context.Context, request *contracts.ActionEvent) (*contracts.ActionEventResponse, error) {
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
s.l.Debug().Msgf("Received step started event for step run %s", request.StepRunId)
|
||||
|
||||
startedAt := request.EventTimestamp.AsTime()
|
||||
@@ -254,7 +259,7 @@ func (s *DispatcherImpl) handleStepRunStarted(ctx context.Context, request *cont
|
||||
})
|
||||
|
||||
metadata, _ := datautils.ToJSONMap(tasktypes.StepRunStartedTaskMetadata{
|
||||
TenantId: request.TenantId,
|
||||
TenantId: tenant.ID,
|
||||
})
|
||||
|
||||
// send the event to the jobs queue
|
||||
@@ -270,12 +275,14 @@ func (s *DispatcherImpl) handleStepRunStarted(ctx context.Context, request *cont
|
||||
}
|
||||
|
||||
return &contracts.ActionEventResponse{
|
||||
TenantId: request.TenantId,
|
||||
TenantId: tenant.ID,
|
||||
WorkerId: request.WorkerId,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *DispatcherImpl) handleStepRunCompleted(ctx context.Context, request *contracts.ActionEvent) (*contracts.ActionEventResponse, error) {
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
s.l.Debug().Msgf("Received step completed event for step run %s", request.StepRunId)
|
||||
|
||||
finishedAt := request.EventTimestamp.AsTime()
|
||||
@@ -287,7 +294,7 @@ func (s *DispatcherImpl) handleStepRunCompleted(ctx context.Context, request *co
|
||||
})
|
||||
|
||||
metadata, _ := datautils.ToJSONMap(tasktypes.StepRunFinishedTaskMetadata{
|
||||
TenantId: request.TenantId,
|
||||
TenantId: tenant.ID,
|
||||
})
|
||||
|
||||
// send the event to the jobs queue
|
||||
@@ -303,12 +310,14 @@ func (s *DispatcherImpl) handleStepRunCompleted(ctx context.Context, request *co
|
||||
}
|
||||
|
||||
return &contracts.ActionEventResponse{
|
||||
TenantId: request.TenantId,
|
||||
TenantId: tenant.ID,
|
||||
WorkerId: request.WorkerId,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *DispatcherImpl) handleStepRunFailed(ctx context.Context, request *contracts.ActionEvent) (*contracts.ActionEventResponse, error) {
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
s.l.Debug().Msgf("Received step failed event for step run %s", request.StepRunId)
|
||||
|
||||
failedAt := request.EventTimestamp.AsTime()
|
||||
@@ -320,7 +329,7 @@ func (s *DispatcherImpl) handleStepRunFailed(ctx context.Context, request *contr
|
||||
})
|
||||
|
||||
metadata, _ := datautils.ToJSONMap(tasktypes.StepRunFailedTaskMetadata{
|
||||
TenantId: request.TenantId,
|
||||
TenantId: tenant.ID,
|
||||
})
|
||||
|
||||
// send the event to the jobs queue
|
||||
@@ -336,7 +345,7 @@ func (s *DispatcherImpl) handleStepRunFailed(ctx context.Context, request *contr
|
||||
}
|
||||
|
||||
return &contracts.ActionEventResponse{
|
||||
TenantId: request.TenantId,
|
||||
TenantId: tenant.ID,
|
||||
WorkerId: request.WorkerId,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
|
||||
"github.com/rs/zerolog"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/internal/config/server"
|
||||
)
|
||||
|
||||
type GRPCAuthN struct {
|
||||
config *server.ServerConfig
|
||||
|
||||
l *zerolog.Logger
|
||||
}
|
||||
|
||||
func NewAuthN(config *server.ServerConfig) *GRPCAuthN {
|
||||
return &GRPCAuthN{
|
||||
config: config,
|
||||
l: config.Logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *GRPCAuthN) Middleware(ctx context.Context) (context.Context, error) {
|
||||
forbidden := status.Errorf(codes.Unauthenticated, "invalid auth token")
|
||||
token, err := auth.AuthFromMD(ctx, "bearer")
|
||||
|
||||
if err != nil {
|
||||
a.l.Debug().Err(err).Msg("error getting bearer token from request")
|
||||
return nil, forbidden
|
||||
}
|
||||
|
||||
tenantId, err := a.config.Auth.JWTManager.ValidateTenantToken(token)
|
||||
|
||||
if err != nil {
|
||||
a.l.Debug().Err(err).Msg("error validating tenant token")
|
||||
|
||||
return nil, forbidden
|
||||
}
|
||||
|
||||
// get the tenant id
|
||||
queriedTenant, err := a.config.Repository.Tenant().GetTenantByID(tenantId)
|
||||
|
||||
if err != nil {
|
||||
a.l.Debug().Err(err).Msg("error getting tenant by id")
|
||||
return nil, forbidden
|
||||
}
|
||||
|
||||
return context.WithValue(ctx, "tenant", queriedTenant), nil
|
||||
}
|
||||
@@ -6,16 +6,19 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
|
||||
"github.com/rs/zerolog"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/internal/config/server"
|
||||
"github.com/hatchet-dev/hatchet/internal/logger"
|
||||
"github.com/hatchet-dev/hatchet/internal/services/admin"
|
||||
admincontracts "github.com/hatchet-dev/hatchet/internal/services/admin/contracts"
|
||||
"github.com/hatchet-dev/hatchet/internal/services/dispatcher"
|
||||
dispatchercontracts "github.com/hatchet-dev/hatchet/internal/services/dispatcher/contracts"
|
||||
"github.com/hatchet-dev/hatchet/internal/services/grpc/middleware"
|
||||
"github.com/hatchet-dev/hatchet/internal/services/ingestor"
|
||||
eventcontracts "github.com/hatchet-dev/hatchet/internal/services/ingestor/contracts"
|
||||
)
|
||||
@@ -29,6 +32,7 @@ type Server struct {
|
||||
port int
|
||||
bindAddress string
|
||||
|
||||
config *server.ServerConfig
|
||||
ingestor ingestor.Ingestor
|
||||
dispatcher dispatcher.Dispatcher
|
||||
admin admin.AdminService
|
||||
@@ -39,6 +43,7 @@ type Server struct {
|
||||
type ServerOpt func(*ServerOpts)
|
||||
|
||||
type ServerOpts struct {
|
||||
config *server.ServerConfig
|
||||
l *zerolog.Logger
|
||||
port int
|
||||
bindAddress string
|
||||
@@ -84,6 +89,12 @@ func WithIngestor(i ingestor.Ingestor) ServerOpt {
|
||||
}
|
||||
}
|
||||
|
||||
func WithConfig(config *server.ServerConfig) ServerOpt {
|
||||
return func(opts *ServerOpts) {
|
||||
opts.config = config
|
||||
}
|
||||
}
|
||||
|
||||
func WithTLSConfig(tls *tls.Config) ServerOpt {
|
||||
return func(opts *ServerOpts) {
|
||||
opts.tls = tls
|
||||
@@ -115,6 +126,10 @@ func NewServer(fs ...ServerOpt) (*Server, error) {
|
||||
f(opts)
|
||||
}
|
||||
|
||||
if opts.config == nil {
|
||||
return nil, fmt.Errorf("config is required. use WithConfig")
|
||||
}
|
||||
|
||||
if opts.tls == nil {
|
||||
return nil, fmt.Errorf("tls config is required. use WithTLSConfig")
|
||||
}
|
||||
@@ -124,6 +139,7 @@ func NewServer(fs ...ServerOpt) (*Server, error) {
|
||||
|
||||
return &Server{
|
||||
l: opts.l,
|
||||
config: opts.config,
|
||||
port: opts.port,
|
||||
bindAddress: opts.bindAddress,
|
||||
ingestor: opts.ingestor,
|
||||
@@ -155,6 +171,16 @@ func (s *Server) startGRPC(ctx context.Context) error {
|
||||
serverOpts = append(serverOpts, grpc.Creds(credentials.NewTLS(s.tls)))
|
||||
}
|
||||
|
||||
authMiddleware := middleware.NewAuthN(s.config)
|
||||
|
||||
serverOpts = append(serverOpts, grpc.StreamInterceptor(
|
||||
auth.StreamServerInterceptor(authMiddleware.Middleware),
|
||||
))
|
||||
|
||||
serverOpts = append(serverOpts, grpc.UnaryInterceptor(
|
||||
auth.UnaryServerInterceptor(authMiddleware.Middleware),
|
||||
))
|
||||
|
||||
grpcServer := grpc.NewServer(serverOpts...)
|
||||
|
||||
if s.ingestor != nil {
|
||||
|
||||
@@ -110,14 +110,12 @@ type PushEventRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// the tenant id
|
||||
TenantId string `protobuf:"bytes,1,opt,name=tenantId,proto3" json:"tenantId,omitempty"`
|
||||
// the key for the event
|
||||
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
// the payload for the event
|
||||
Payload string `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||
Payload string `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||
// when the event was generated
|
||||
EventTimestamp *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=eventTimestamp,proto3" json:"eventTimestamp,omitempty"`
|
||||
EventTimestamp *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=eventTimestamp,proto3" json:"eventTimestamp,omitempty"`
|
||||
}
|
||||
|
||||
func (x *PushEventRequest) Reset() {
|
||||
@@ -152,13 +150,6 @@ func (*PushEventRequest) Descriptor() ([]byte, []int) {
|
||||
return file_events_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *PushEventRequest) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PushEventRequest) GetKey() string {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
@@ -185,12 +176,10 @@ type ListEventRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// (required) the tenant id
|
||||
TenantId string `protobuf:"bytes,1,opt,name=tenantId,proto3" json:"tenantId,omitempty"`
|
||||
// (optional) the number of events to skip
|
||||
Offset int32 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"`
|
||||
Offset int32 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"`
|
||||
// (optional) the key for the event
|
||||
Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ListEventRequest) Reset() {
|
||||
@@ -225,13 +214,6 @@ func (*ListEventRequest) Descriptor() ([]byte, []int) {
|
||||
return file_events_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *ListEventRequest) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ListEventRequest) GetOffset() int32 {
|
||||
if x != nil {
|
||||
return x.Offset
|
||||
@@ -299,10 +281,8 @@ type ReplayEventRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// the tenant id
|
||||
TenantId string `protobuf:"bytes,1,opt,name=tenantId,proto3" json:"tenantId,omitempty"`
|
||||
// the event id to replay
|
||||
EventId string `protobuf:"bytes,2,opt,name=eventId,proto3" json:"eventId,omitempty"`
|
||||
EventId string `protobuf:"bytes,1,opt,name=eventId,proto3" json:"eventId,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ReplayEventRequest) Reset() {
|
||||
@@ -337,13 +317,6 @@ func (*ReplayEventRequest) Descriptor() ([]byte, []int) {
|
||||
return file_events_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *ReplayEventRequest) GetTenantId() string {
|
||||
if x != nil {
|
||||
return x.TenantId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ReplayEventRequest) GetEventId() string {
|
||||
if x != nil {
|
||||
return x.EventId
|
||||
@@ -368,45 +341,40 @@ var file_events_proto_rawDesc = []byte{
|
||||
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
|
||||
0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22,
|
||||
0x9e, 0x01, 0x0a, 0x10, 0x50, 0x75, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64,
|
||||
0x82, 0x01, 0x0a, 0x10, 0x50, 0x75, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61,
|
||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
|
||||
0x12, 0x42, 0x0a, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
||||
0x6d, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73,
|
||||
0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73,
|
||||
0x74, 0x61, 0x6d, 0x70, 0x22, 0x3c, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73,
|
||||
0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74,
|
||||
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
|
||||
0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x42, 0x0a, 0x0e,
|
||||
0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
|
||||
0x52, 0x0e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
|
||||
0x22, 0x58, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64,
|
||||
0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
|
||||
0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x33, 0x0a, 0x11, 0x4c, 0x69,
|
||||
0x73, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x1e, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x06, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22,
|
||||
0x4a, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49,
|
||||
0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x32, 0x99, 0x01, 0x0a, 0x0d,
|
||||
0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x23, 0x0a,
|
||||
0x04, 0x50, 0x75, 0x73, 0x68, 0x12, 0x11, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x06, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74,
|
||||
0x22, 0x00, 0x12, 0x2f, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x11, 0x2e, 0x4c, 0x69, 0x73,
|
||||
0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e,
|
||||
0x4c, 0x69, 0x73, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x53, 0x69, 0x6e,
|
||||
0x67, 0x6c, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x13, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61,
|
||||
0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x06, 0x2e,
|
||||
0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x00, 0x42, 0x47, 0x5a, 0x45, 0x67, 0x69, 0x74, 0x68, 0x75,
|
||||
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65,
|
||||
0x76, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
||||
0x61, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x70,
|
||||
0x61, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x65, 0x79, 0x22, 0x33, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74,
|
||||
0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52,
|
||||
0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x2e, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6c, 0x61,
|
||||
0x79, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a,
|
||||
0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||
0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x32, 0x99, 0x01, 0x0a, 0x0d, 0x45, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x50, 0x75, 0x73,
|
||||
0x68, 0x12, 0x11, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x06, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x00, 0x12, 0x2f,
|
||||
0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x11, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x76, 0x65,
|
||||
0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
|
||||
0x32, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x45,
|
||||
0x76, 0x65, 0x6e, 0x74, 0x12, 0x13, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x79, 0x45, 0x76, 0x65,
|
||||
0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x06, 0x2e, 0x45, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x22, 0x00, 0x42, 0x47, 0x5a, 0x45, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x2f, 0x68, 0x61, 0x74, 0x63, 0x68, 0x65, 0x74, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x68, 0x61,
|
||||
0x74, 0x63, 0x68, 0x65, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68,
|
||||
0x65, 0x72, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x73, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -16,6 +16,8 @@ import (
|
||||
)
|
||||
|
||||
func (i *IngestorImpl) Push(ctx context.Context, req *contracts.PushEventRequest) (*contracts.Event, error) {
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
eventDataMap := map[string]interface{}{}
|
||||
|
||||
err := json.Unmarshal([]byte(req.Payload), &eventDataMap)
|
||||
@@ -24,7 +26,7 @@ func (i *IngestorImpl) Push(ctx context.Context, req *contracts.PushEventRequest
|
||||
return nil, err
|
||||
}
|
||||
|
||||
event, err := i.IngestEvent(ctx, req.TenantId, req.Key, eventDataMap)
|
||||
event, err := i.IngestEvent(ctx, tenant.ID, req.Key, eventDataMap)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -40,6 +42,8 @@ func (i *IngestorImpl) Push(ctx context.Context, req *contracts.PushEventRequest
|
||||
}
|
||||
|
||||
func (i *IngestorImpl) List(ctx context.Context, req *contracts.ListEventRequest) (*contracts.ListEventResponse, error) {
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
offset := int(req.Offset)
|
||||
var keys []string
|
||||
|
||||
@@ -47,7 +51,7 @@ func (i *IngestorImpl) List(ctx context.Context, req *contracts.ListEventRequest
|
||||
keys = []string{req.Key}
|
||||
}
|
||||
|
||||
listResult, err := i.eventRepository.ListEvents(req.TenantId, &repository.ListEventOpts{
|
||||
listResult, err := i.eventRepository.ListEvents(tenant.ID, &repository.ListEventOpts{
|
||||
Keys: keys,
|
||||
Offset: &offset,
|
||||
})
|
||||
@@ -74,13 +78,15 @@ func (i *IngestorImpl) List(ctx context.Context, req *contracts.ListEventRequest
|
||||
}
|
||||
|
||||
func (i *IngestorImpl) ReplaySingleEvent(ctx context.Context, req *contracts.ReplayEventRequest) (*contracts.Event, error) {
|
||||
tenant := ctx.Value("tenant").(*db.TenantModel)
|
||||
|
||||
oldEvent, err := i.eventRepository.GetEventById(req.EventId)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newEvent, err := i.IngestReplayedEvent(ctx, req.TenantId, oldEvent)
|
||||
newEvent, err := i.IngestReplayedEvent(ctx, tenant.ID, oldEvent)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -11,7 +11,5 @@ func Prepare(t *testing.T) {
|
||||
_ = os.Setenv("HATCHET_CLIENT_TENANT_ID", "707d0855-80ab-4e1f-a156-f1c4546cbf52")
|
||||
_ = os.Setenv("DATABASE_URL", "postgresql://hatchet:hatchet@127.0.0.1:5431/hatchet")
|
||||
_ = os.Setenv("HATCHET_CLIENT_TLS_ROOT_CA_FILE", "../../hack/dev/certs/ca.cert")
|
||||
_ = os.Setenv("HATCHET_CLIENT_TLS_CERT_FILE", "../../hack/dev/certs/client-worker.pem")
|
||||
_ = os.Setenv("HATCHET_CLIENT_TLS_KEY_FILE", "../../hack/dev/certs/client-worker.key")
|
||||
_ = os.Setenv("HATCHET_CLIENT_TLS_SERVER_NAME", "cluster")
|
||||
}
|
||||
|
||||
+10
-11
@@ -31,6 +31,8 @@ type adminClientImpl struct {
|
||||
l *zerolog.Logger
|
||||
|
||||
v validator.Validator
|
||||
|
||||
ctx *contextLoader
|
||||
}
|
||||
|
||||
func newAdmin(conn *grpc.ClientConn, opts *sharedClientOpts) AdminClient {
|
||||
@@ -39,6 +41,7 @@ func newAdmin(conn *grpc.ClientConn, opts *sharedClientOpts) AdminClient {
|
||||
tenantId: opts.tenantId,
|
||||
l: opts.l,
|
||||
v: opts.v,
|
||||
ctx: opts.ctxLoader,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,9 +78,8 @@ func (a *adminClientImpl) PutWorkflow(workflow *types.Workflow, fs ...PutOptFunc
|
||||
return fmt.Errorf("could not get put opts: %w", err)
|
||||
}
|
||||
|
||||
apiWorkflow, err := a.client.GetWorkflowByName(context.Background(), &admincontracts.GetWorkflowByNameRequest{
|
||||
TenantId: a.tenantId,
|
||||
Name: req.Opts.Name,
|
||||
apiWorkflow, err := a.client.GetWorkflowByName(a.ctx.newContext(context.Background()), &admincontracts.GetWorkflowByNameRequest{
|
||||
Name: req.Opts.Name,
|
||||
})
|
||||
|
||||
shouldPut := opts.autoVersion
|
||||
@@ -114,7 +116,7 @@ func (a *adminClientImpl) PutWorkflow(workflow *types.Workflow, fs ...PutOptFunc
|
||||
}
|
||||
|
||||
if shouldPut {
|
||||
_, err = a.client.PutWorkflow(context.Background(), req)
|
||||
_, err = a.client.PutWorkflow(a.ctx.newContext(context.Background()), req)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create workflow: %w", err)
|
||||
@@ -159,9 +161,8 @@ func (a *adminClientImpl) ScheduleWorkflow(workflowName string, fs ...ScheduleOp
|
||||
}
|
||||
|
||||
// get the workflow id from the name
|
||||
workflow, err := a.client.GetWorkflowByName(context.Background(), &admincontracts.GetWorkflowByNameRequest{
|
||||
TenantId: a.tenantId,
|
||||
Name: workflowName,
|
||||
workflow, err := a.client.GetWorkflowByName(a.ctx.newContext(context.Background()), &admincontracts.GetWorkflowByNameRequest{
|
||||
Name: workflowName,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@@ -180,8 +181,7 @@ func (a *adminClientImpl) ScheduleWorkflow(workflowName string, fs ...ScheduleOp
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = a.client.ScheduleWorkflow(context.Background(), &admincontracts.ScheduleWorkflowRequest{
|
||||
TenantId: a.tenantId,
|
||||
_, err = a.client.ScheduleWorkflow(a.ctx.newContext(context.Background()), &admincontracts.ScheduleWorkflowRequest{
|
||||
WorkflowId: workflow.Id,
|
||||
Schedules: pbSchedules,
|
||||
Input: string(inputBytes),
|
||||
@@ -246,8 +246,7 @@ func (a *adminClientImpl) getPutRequest(workflow *types.Workflow) (*admincontrac
|
||||
opts.Jobs = jobOpts
|
||||
|
||||
return &admincontracts.PutWorkflowRequest{
|
||||
TenantId: a.tenantId,
|
||||
Opts: opts,
|
||||
Opts: opts,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
+14
-6
@@ -45,6 +45,7 @@ type ClientOpts struct {
|
||||
v validator.Validator
|
||||
tls *tls.Config
|
||||
hostPort string
|
||||
token string
|
||||
|
||||
filesLoader filesLoaderFunc
|
||||
initWorkflows bool
|
||||
@@ -64,6 +65,7 @@ func defaultClientOpts() *ClientOpts {
|
||||
|
||||
return &ClientOpts{
|
||||
tenantId: clientConfig.TenantId,
|
||||
token: clientConfig.Token,
|
||||
l: &logger,
|
||||
v: validator.NewDefaultValidator(),
|
||||
tls: clientConfig.TLSConfig,
|
||||
@@ -101,9 +103,10 @@ func WithWorkflows(files []*types.Workflow) ClientOpt {
|
||||
}
|
||||
|
||||
type sharedClientOpts struct {
|
||||
tenantId string
|
||||
l *zerolog.Logger
|
||||
v validator.Validator
|
||||
tenantId string
|
||||
l *zerolog.Logger
|
||||
v validator.Validator
|
||||
ctxLoader *contextLoader
|
||||
}
|
||||
|
||||
// New creates a new client instance.
|
||||
@@ -119,6 +122,10 @@ func New(fs ...ClientOpt) (Client, error) {
|
||||
return nil, fmt.Errorf("tls config is required")
|
||||
}
|
||||
|
||||
if opts.token == "" {
|
||||
return nil, fmt.Errorf("token is required")
|
||||
}
|
||||
|
||||
opts.l.Debug().Msgf("connecting to %s with TLS server name %s", opts.hostPort, opts.tls.ServerName)
|
||||
|
||||
conn, err := grpc.Dial(
|
||||
@@ -131,9 +138,10 @@ func New(fs ...ClientOpt) (Client, error) {
|
||||
}
|
||||
|
||||
shared := &sharedClientOpts{
|
||||
tenantId: opts.tenantId,
|
||||
l: opts.l,
|
||||
v: opts.v,
|
||||
tenantId: opts.tenantId,
|
||||
l: opts.l,
|
||||
v: opts.v,
|
||||
ctxLoader: newContextLoader(opts.token),
|
||||
}
|
||||
|
||||
admin := newAdmin(conn, shared)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
grpcMetadata "google.golang.org/grpc/metadata"
|
||||
|
||||
"context"
|
||||
)
|
||||
|
||||
type contextLoader struct {
|
||||
// The token
|
||||
Token string
|
||||
}
|
||||
|
||||
func newContextLoader(token string) *contextLoader {
|
||||
return &contextLoader{
|
||||
Token: token,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *contextLoader) newContext(ctx context.Context) context.Context {
|
||||
md := grpcMetadata.New(map[string]string{
|
||||
"authorization": "Bearer " + c.Token,
|
||||
})
|
||||
|
||||
return grpcMetadata.NewOutgoingContext(ctx, md)
|
||||
}
|
||||
+11
-10
@@ -123,6 +123,8 @@ type dispatcherClientImpl struct {
|
||||
l *zerolog.Logger
|
||||
|
||||
v validator.Validator
|
||||
|
||||
ctx *contextLoader
|
||||
}
|
||||
|
||||
func newDispatcher(conn *grpc.ClientConn, opts *sharedClientOpts) DispatcherClient {
|
||||
@@ -131,6 +133,7 @@ func newDispatcher(conn *grpc.ClientConn, opts *sharedClientOpts) DispatcherClie
|
||||
tenantId: opts.tenantId,
|
||||
l: opts.l,
|
||||
v: opts.v,
|
||||
ctx: opts.ctxLoader,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +149,8 @@ type actionListenerImpl struct {
|
||||
l *zerolog.Logger
|
||||
|
||||
v validator.Validator
|
||||
|
||||
ctx *contextLoader
|
||||
}
|
||||
|
||||
func (d *dispatcherClientImpl) newActionListener(ctx context.Context, req *GetActionListenerRequest) (*actionListenerImpl, error) {
|
||||
@@ -155,8 +160,7 @@ func (d *dispatcherClientImpl) newActionListener(ctx context.Context, req *GetAc
|
||||
}
|
||||
|
||||
// register the worker
|
||||
resp, err := d.client.Register(ctx, &dispatchercontracts.WorkerRegisterRequest{
|
||||
TenantId: d.tenantId,
|
||||
resp, err := d.client.Register(d.ctx.newContext(ctx), &dispatchercontracts.WorkerRegisterRequest{
|
||||
WorkerName: req.WorkerName,
|
||||
Actions: req.Actions,
|
||||
Services: req.Services,
|
||||
@@ -169,8 +173,7 @@ func (d *dispatcherClientImpl) newActionListener(ctx context.Context, req *GetAc
|
||||
d.l.Debug().Msgf("Registered worker with id: %s", resp.WorkerId)
|
||||
|
||||
// subscribe to the worker
|
||||
listener, err := d.client.Listen(ctx, &dispatchercontracts.WorkerListenRequest{
|
||||
TenantId: d.tenantId,
|
||||
listener, err := d.client.Listen(d.ctx.newContext(ctx), &dispatchercontracts.WorkerListenRequest{
|
||||
WorkerId: resp.WorkerId,
|
||||
})
|
||||
|
||||
@@ -185,6 +188,7 @@ func (d *dispatcherClientImpl) newActionListener(ctx context.Context, req *GetAc
|
||||
l: d.l,
|
||||
v: d.v,
|
||||
tenantId: d.tenantId,
|
||||
ctx: d.ctx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -279,8 +283,7 @@ func (a *actionListenerImpl) retrySubscribe(ctx context.Context) error {
|
||||
for retries < DefaultActionListenerRetryCount {
|
||||
time.Sleep(DefaultActionListenerRetryInterval)
|
||||
|
||||
listenClient, err := a.client.Listen(ctx, &dispatchercontracts.WorkerListenRequest{
|
||||
TenantId: a.tenantId,
|
||||
listenClient, err := a.client.Listen(a.ctx.newContext(ctx), &dispatchercontracts.WorkerListenRequest{
|
||||
WorkerId: a.workerId,
|
||||
})
|
||||
|
||||
@@ -300,9 +303,8 @@ func (a *actionListenerImpl) retrySubscribe(ctx context.Context) error {
|
||||
|
||||
func (a *actionListenerImpl) Unregister() error {
|
||||
_, err := a.client.Unsubscribe(
|
||||
context.Background(),
|
||||
a.ctx.newContext(context.Background()),
|
||||
&dispatchercontracts.WorkerUnsubscribeRequest{
|
||||
TenantId: a.tenantId,
|
||||
WorkerId: a.workerId,
|
||||
},
|
||||
)
|
||||
@@ -343,8 +345,7 @@ func (d *dispatcherClientImpl) SendActionEvent(ctx context.Context, in *ActionEv
|
||||
actionEventType = dispatchercontracts.ActionEventType_STEP_EVENT_TYPE_UNKNOWN
|
||||
}
|
||||
|
||||
resp, err := d.client.SendActionEvent(ctx, &dispatchercontracts.ActionEvent{
|
||||
TenantId: d.tenantId,
|
||||
resp, err := d.client.SendActionEvent(d.ctx.newContext(ctx), &dispatchercontracts.ActionEvent{
|
||||
WorkerId: in.WorkerId,
|
||||
JobId: in.JobId,
|
||||
JobRunId: in.JobRunId,
|
||||
|
||||
+4
-2
@@ -24,6 +24,8 @@ type eventClientImpl struct {
|
||||
l *zerolog.Logger
|
||||
|
||||
v validator.Validator
|
||||
|
||||
ctx *contextLoader
|
||||
}
|
||||
|
||||
func newEvent(conn *grpc.ClientConn, opts *sharedClientOpts) EventClient {
|
||||
@@ -32,6 +34,7 @@ func newEvent(conn *grpc.ClientConn, opts *sharedClientOpts) EventClient {
|
||||
tenantId: opts.tenantId,
|
||||
l: opts.l,
|
||||
v: opts.v,
|
||||
ctx: opts.ctxLoader,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,8 +45,7 @@ func (a *eventClientImpl) Push(ctx context.Context, eventKey string, payload int
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = a.client.Push(ctx, &eventcontracts.PushEventRequest{
|
||||
TenantId: a.tenantId,
|
||||
_, err = a.client.Push(a.ctx.newContext(ctx), &eventcontracts.PushEventRequest{
|
||||
Key: eventKey,
|
||||
Payload: string(payloadBytes),
|
||||
EventTimestamp: timestamppb.Now(),
|
||||
|
||||
@@ -2,7 +2,9 @@ package loader
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/internal/config/client"
|
||||
"github.com/hatchet-dev/hatchet/internal/config/loader/loaderutils"
|
||||
@@ -41,7 +43,21 @@ func LoadClientConfigFile(files ...[]byte) (*client.ClientConfigFile, error) {
|
||||
}
|
||||
|
||||
func GetClientConfigFromConfigFile(cf *client.ClientConfigFile) (res *client.ClientConfig, err error) {
|
||||
tlsConf, err := loaderutils.LoadClientTLSConfig(&cf.TLS)
|
||||
tlsServerName := cf.TLS.TLSServerName
|
||||
|
||||
// if the tls server name is empty, parse the domain from the host:port
|
||||
if tlsServerName == "" {
|
||||
// parse the domain from the host:port
|
||||
domain, err := parseDomain(cf.HostPort)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse domain: %w", err)
|
||||
}
|
||||
|
||||
tlsServerName = domain.Hostname()
|
||||
}
|
||||
|
||||
tlsConf, err := loaderutils.LoadClientTLSConfig(&cf.TLS, tlsServerName)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not load TLS config: %w", err)
|
||||
@@ -50,5 +66,13 @@ func GetClientConfigFromConfigFile(cf *client.ClientConfigFile) (res *client.Cli
|
||||
return &client.ClientConfig{
|
||||
TenantId: cf.TenantId,
|
||||
TLSConfig: tlsConf,
|
||||
Token: cf.Token,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseDomain(domain string) (*url.URL, error) {
|
||||
if !strings.HasPrefix(domain, "http://") && !strings.HasPrefix(domain, "https://") {
|
||||
domain = "https://" + domain
|
||||
}
|
||||
return url.Parse(domain)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- The primary key for the `Action` table will be changed. If it partially fails, the table could be left without primary key constraint.
|
||||
- The `refreshToken` column on the `UserOAuth` table would be dropped and recreated. This will lead to data loss if there is data in the column.
|
||||
- A unique constraint covering the columns `[id]` on the table `Action` will be added. If there are existing duplicate values, this will fail.
|
||||
- A unique constraint covering the columns `[tenantId,actionId]` on the table `Action` will be added. If there are existing duplicate values, this will fail.
|
||||
- Added the required column `actionId` to the `Action` table without a default value. This is not possible if the table is not empty.
|
||||
- Changed the type of `id` on the `Action` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required.
|
||||
- Changed the type of `accessToken` on the `UserOAuth` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required.
|
||||
- Changed the type of `A` on the `_ActionToWorker` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Step" DROP CONSTRAINT "Step_actionId_tenantId_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "_ActionToWorker" DROP CONSTRAINT "_ActionToWorker_A_fkey";
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "Action_tenantId_id_key";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Action" DROP CONSTRAINT "Action_pkey",
|
||||
ADD COLUMN "actionId" TEXT NOT NULL,
|
||||
DROP COLUMN "id",
|
||||
ADD COLUMN "id" UUID NOT NULL,
|
||||
ADD CONSTRAINT "Action_pkey" PRIMARY KEY ("id");
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "UserOAuth" DROP COLUMN "accessToken",
|
||||
ADD COLUMN "accessToken" BYTEA NOT NULL,
|
||||
DROP COLUMN "refreshToken",
|
||||
ADD COLUMN "refreshToken" BYTEA;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "_ActionToWorker" DROP COLUMN "A",
|
||||
ADD COLUMN "A" UUID NOT NULL;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "APIToken" (
|
||||
"id" UUID NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"expiresAt" TIMESTAMP(3),
|
||||
"revoked" BOOLEAN NOT NULL DEFAULT false,
|
||||
"name" TEXT,
|
||||
"tenantId" UUID,
|
||||
|
||||
CONSTRAINT "APIToken_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "APIToken_id_key" ON "APIToken"("id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Action_id_key" ON "Action"("id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Action_tenantId_actionId_key" ON "Action"("tenantId", "actionId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "_ActionToWorker_AB_unique" ON "_ActionToWorker"("A", "B");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "APIToken" ADD CONSTRAINT "APIToken_tenantId_fkey" FOREIGN KEY ("tenantId") REFERENCES "Tenant"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Step" ADD CONSTRAINT "Step_actionId_tenantId_fkey" FOREIGN KEY ("actionId", "tenantId") REFERENCES "Action"("actionId", "tenantId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ActionToWorker" ADD CONSTRAINT "_ActionToWorker_A_fkey" FOREIGN KEY ("A") REFERENCES "Action"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
+27
-5
@@ -53,10 +53,10 @@ model UserOAuth {
|
||||
providerUserId String
|
||||
|
||||
// the oauth provider's access token
|
||||
accessToken String
|
||||
accessToken Bytes @db.ByteA
|
||||
|
||||
// the oauth provider's refresh token
|
||||
refreshToken String?
|
||||
refreshToken Bytes? @db.ByteA
|
||||
|
||||
// the oauth provider's expiry time
|
||||
expiresAt DateTime?
|
||||
@@ -117,6 +117,7 @@ model Tenant {
|
||||
actions Action[]
|
||||
services Service[]
|
||||
invites TenantInviteLink[]
|
||||
apiTokens APIToken[]
|
||||
}
|
||||
|
||||
enum TenantMemberRole {
|
||||
@@ -169,6 +170,25 @@ model TenantInviteLink {
|
||||
role TenantMemberRole @default(OWNER)
|
||||
}
|
||||
|
||||
model APIToken {
|
||||
// base fields
|
||||
id String @id @unique @default(uuid()) @db.Uuid
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @default(now()) @updatedAt
|
||||
|
||||
// when it expires
|
||||
expiresAt DateTime?
|
||||
|
||||
// whether the token has been revoked
|
||||
revoked Boolean @default(false)
|
||||
|
||||
// an optional name for the token
|
||||
name String?
|
||||
|
||||
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
||||
tenantId String? @db.Uuid
|
||||
}
|
||||
|
||||
// Event represents an event in the database.
|
||||
model Event {
|
||||
// base fields
|
||||
@@ -385,7 +405,9 @@ model Job {
|
||||
|
||||
model Action {
|
||||
// base fields
|
||||
id String @id
|
||||
id String @id @unique @default(uuid()) @db.Uuid
|
||||
|
||||
actionId String
|
||||
|
||||
// the action description
|
||||
description String?
|
||||
@@ -400,7 +422,7 @@ model Action {
|
||||
workers Worker[]
|
||||
|
||||
// actions are unique per tenant
|
||||
@@unique([tenantId, id])
|
||||
@@unique([tenantId, actionId])
|
||||
}
|
||||
|
||||
model Step {
|
||||
@@ -422,7 +444,7 @@ model Step {
|
||||
jobId String @db.Uuid
|
||||
|
||||
// an action id for the step
|
||||
action Action @relation(fields: [actionId, tenantId], references: [id, tenantId])
|
||||
action Action @relation(fields: [actionId, tenantId], references: [actionId, tenantId])
|
||||
actionId String
|
||||
|
||||
timeout String?
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
#
|
||||
# Builds python auto-generated protobuf files
|
||||
|
||||
poetry run python -m grpc_tools.protoc --proto_path=../api-contracts/dispatcher --python_out=./hatchet --pyi_out=./hatchet --grpc_python_out=./hatchet dispatcher.proto
|
||||
poetry run python -m grpc_tools.protoc --proto_path=../api-contracts/events --python_out=./hatchet --pyi_out=./hatchet --grpc_python_out=./hatchet events.proto
|
||||
poetry run python -m grpc_tools.protoc --proto_path=../api-contracts/workflows --python_out=./hatchet --pyi_out=./hatchet --grpc_python_out=./hatchet workflows.proto
|
||||
poetry run python -m grpc_tools.protoc --proto_path=../api-contracts/dispatcher --python_out=./hatchet_sdk --pyi_out=./hatchet_sdk --grpc_python_out=./hatchet_sdk dispatcher.proto
|
||||
poetry run python -m grpc_tools.protoc --proto_path=../api-contracts/events --python_out=./hatchet_sdk --pyi_out=./hatchet_sdk --grpc_python_out=./hatchet_sdk events.proto
|
||||
poetry run python -m grpc_tools.protoc --proto_path=../api-contracts/workflows --python_out=./hatchet_sdk --pyi_out=./hatchet_sdk --grpc_python_out=./hatchet_sdk workflows.proto
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# relative imports
|
||||
from typing import Any
|
||||
from .clients.admin import AdminClientImpl, new_admin
|
||||
from .clients.events import EventClientImpl, new_event
|
||||
from .clients.dispatcher import DispatcherClientImpl, new_dispatcher
|
||||
@@ -53,14 +54,27 @@ def new_client(*opts_functions):
|
||||
|
||||
if config.host_port is None:
|
||||
raise ValueError("Host and port are required")
|
||||
|
||||
root = open(config.tls_config.ca_file, "rb").read()
|
||||
private_key = open(config.tls_config.key_file, "rb").read()
|
||||
certificate_chain = open(config.tls_config.cert_file, "rb").read()
|
||||
|
||||
credentials : grpc.ChannelCredentials | None = None
|
||||
|
||||
# load channel credentials
|
||||
if config.tls_config.tls_strategy == 'tls':
|
||||
root : Any | None = None
|
||||
|
||||
if config.tls_config.ca_file:
|
||||
root = open(config.tls_config.ca_file, "rb").read()
|
||||
|
||||
credentials = grpc.ssl_channel_credentials(root_certificates=root)
|
||||
elif config.tls_config.tls_strategy == 'mtls':
|
||||
root = open(config.tls_config.ca_file, "rb").read()
|
||||
private_key = open(config.tls_config.key_file, "rb").read()
|
||||
certificate_chain = open(config.tls_config.cert_file, "rb").read()
|
||||
|
||||
credentials = grpc.ssl_channel_credentials(root_certificates=root, private_key=private_key, certificate_chain=certificate_chain)
|
||||
|
||||
conn = grpc.secure_channel(
|
||||
target=config.host_port,
|
||||
credentials=grpc.ssl_channel_credentials(root_certificates=root, private_key=private_key, certificate_chain=certificate_chain),
|
||||
credentials=credentials,
|
||||
options=[('grpc.ssl_target_name_override', config.tls_config.server_name)],
|
||||
)
|
||||
|
||||
|
||||
@@ -5,21 +5,19 @@ from ..workflows_pb2_grpc import WorkflowServiceStub
|
||||
from ..workflows_pb2 import CreateWorkflowVersionOpts, ScheduleWorkflowRequest, PutWorkflowRequest, GetWorkflowByNameRequest, Workflow
|
||||
from ..loader import ClientConfig
|
||||
from ..semver import bump_minor_version
|
||||
from ..metadata import get_metadata
|
||||
|
||||
|
||||
def new_admin(conn, config: ClientConfig):
|
||||
return AdminClientImpl(
|
||||
client=WorkflowServiceStub(conn),
|
||||
tenant_id=config.tenant_id,
|
||||
# logger=shared_opts['logger'],
|
||||
# validator=shared_opts['validator'],
|
||||
token=config.token,
|
||||
)
|
||||
|
||||
class AdminClientImpl:
|
||||
def __init__(self, client : WorkflowServiceStub, tenant_id):
|
||||
def __init__(self, client : WorkflowServiceStub, token):
|
||||
self.client = client
|
||||
self.tenant_id = tenant_id
|
||||
# self.logger = logger
|
||||
# self.validator = validator
|
||||
self.token = token
|
||||
|
||||
def put_workflow(self, workflow: CreateWorkflowVersionOpts, auto_version: bool = False):
|
||||
if workflow.version == "" and not auto_version:
|
||||
@@ -31,9 +29,9 @@ class AdminClientImpl:
|
||||
try:
|
||||
existing_workflow : Workflow = self.client.GetWorkflowByName(
|
||||
GetWorkflowByNameRequest(
|
||||
tenant_id=self.tenant_id,
|
||||
name=workflow.name,
|
||||
)
|
||||
),
|
||||
metadata=get_metadata(self.token),
|
||||
)
|
||||
except grpc.RpcError as e:
|
||||
if e.code() == grpc.StatusCode.NOT_FOUND:
|
||||
@@ -63,9 +61,9 @@ class AdminClientImpl:
|
||||
try:
|
||||
self.client.PutWorkflow(
|
||||
PutWorkflowRequest(
|
||||
tenant_id=self.tenant_id,
|
||||
opts=workflow,
|
||||
)
|
||||
),
|
||||
metadata=get_metadata(self.token),
|
||||
)
|
||||
except grpc.RpcError as e:
|
||||
raise ValueError(f"Could not create/update workflow: {e}")
|
||||
@@ -76,6 +74,6 @@ class AdminClientImpl:
|
||||
tenant_id=self.tenant_id,
|
||||
workflow_id=workflow_id,
|
||||
schedules=schedules,
|
||||
))
|
||||
), metadata=get_metadata(self.token))
|
||||
except grpc.RpcError as e:
|
||||
raise ValueError(f"gRPC error: {e}")
|
||||
|
||||
@@ -8,13 +8,13 @@ from ..logger import logger
|
||||
import json
|
||||
import grpc
|
||||
from typing import Callable, List, Union
|
||||
from ..metadata import get_metadata
|
||||
|
||||
|
||||
def new_dispatcher(conn, config: ClientConfig):
|
||||
return DispatcherClientImpl(
|
||||
client=DispatcherStub(conn),
|
||||
tenant_id=config.tenant_id,
|
||||
# logger=shared_opts['logger'],
|
||||
# validator=shared_opts['validator'],
|
||||
token=config.token,
|
||||
)
|
||||
|
||||
class DispatcherClient:
|
||||
@@ -60,9 +60,9 @@ START_STEP_RUN = 0
|
||||
CANCEL_STEP_RUN = 1
|
||||
|
||||
class ActionListenerImpl(WorkerActionListener):
|
||||
def __init__(self, client : DispatcherStub, tenant_id, worker_id):
|
||||
def __init__(self, client : DispatcherStub, token, worker_id):
|
||||
self.client = client
|
||||
self.tenant_id = tenant_id
|
||||
self.token = token
|
||||
self.worker_id = worker_id
|
||||
self.retries = 0
|
||||
|
||||
@@ -145,42 +145,43 @@ class ActionListenerImpl(WorkerActionListener):
|
||||
time.sleep(DEFAULT_ACTION_LISTENER_RETRY_INTERVAL)
|
||||
|
||||
return self.client.Listen(WorkerListenRequest(
|
||||
tenantId=self.tenant_id,
|
||||
workerId=self.worker_id
|
||||
), timeout=DEFAULT_ACTION_TIMEOUT)
|
||||
),
|
||||
timeout=DEFAULT_ACTION_TIMEOUT,
|
||||
metadata=get_metadata(self.token),
|
||||
)
|
||||
|
||||
def unregister(self):
|
||||
try:
|
||||
self.client.Unsubscribe(
|
||||
WorkerUnsubscribeRequest(
|
||||
tenantId=self.tenant_id,
|
||||
workerId=self.worker_id
|
||||
),
|
||||
timeout=DEFAULT_REGISTER_TIMEOUT,
|
||||
metadata=get_metadata(self.token),
|
||||
)
|
||||
except grpc.RpcError as e:
|
||||
raise Exception(f"Failed to unsubscribe: {e}")
|
||||
|
||||
class DispatcherClientImpl(DispatcherClient):
|
||||
def __init__(self, client : DispatcherStub, tenant_id):
|
||||
def __init__(self, client : DispatcherStub, token):
|
||||
self.client = client
|
||||
self.tenant_id = tenant_id
|
||||
self.token = token
|
||||
# self.logger = logger
|
||||
# self.validator = validator
|
||||
|
||||
def get_action_listener(self, req: GetActionListenerRequest) -> ActionListenerImpl:
|
||||
# Register the worker
|
||||
response : WorkerRegisterResponse = self.client.Register(WorkerRegisterRequest(
|
||||
tenantId=self.tenant_id,
|
||||
workerName=req.worker_name,
|
||||
actions=req.actions,
|
||||
services=req.services
|
||||
), timeout=DEFAULT_REGISTER_TIMEOUT)
|
||||
), timeout=DEFAULT_REGISTER_TIMEOUT, metadata=get_metadata(self.token))
|
||||
|
||||
return ActionListenerImpl(self.client, self.tenant_id, response.workerId)
|
||||
return ActionListenerImpl(self.client, self.token, response.workerId)
|
||||
|
||||
def send_action_event(self, in_: ActionEvent):
|
||||
response : ActionEventResponse = self.client.SendActionEvent(in_)
|
||||
response : ActionEventResponse = self.client.SendActionEvent(in_, metadata=get_metadata(self.token),)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@@ -6,21 +6,18 @@ from ..loader import ClientConfig
|
||||
import json
|
||||
import grpc
|
||||
from google.protobuf import timestamp_pb2
|
||||
from ..metadata import get_metadata
|
||||
|
||||
def new_event(conn, config: ClientConfig):
|
||||
return EventClientImpl(
|
||||
client=EventsServiceStub(conn),
|
||||
tenant_id=config.tenant_id,
|
||||
# logger=shared_opts['logger'],
|
||||
# validator=shared_opts['validator'],
|
||||
token=config.token,
|
||||
)
|
||||
|
||||
class EventClientImpl:
|
||||
def __init__(self, client, tenant_id):
|
||||
def __init__(self, client, token):
|
||||
self.client = client
|
||||
self.tenant_id = tenant_id
|
||||
# self.logger = logger
|
||||
# self.validator = validator
|
||||
self.token = token
|
||||
|
||||
def push(self, event_key, payload):
|
||||
try:
|
||||
@@ -29,13 +26,12 @@ class EventClientImpl:
|
||||
raise ValueError(f"Error encoding payload: {e}")
|
||||
|
||||
request = PushEventRequest(
|
||||
tenantId=self.tenant_id,
|
||||
key=event_key,
|
||||
payload=payload_bytes,
|
||||
eventTimestamp=timestamp_pb2.Timestamp().FromDatetime(datetime.datetime.now()),
|
||||
)
|
||||
|
||||
try:
|
||||
self.client.Push(request)
|
||||
self.client.Push(request, metadata=get_metadata(self.token))
|
||||
except grpc.RpcError as e:
|
||||
raise ValueError(f"gRPC error: {e}")
|
||||
|
||||
@@ -15,7 +15,7 @@ _sym_db = _symbol_database.Default()
|
||||
from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10\x64ispatcher.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"`\n\x15WorkerRegisterRequest\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x12\n\nworkerName\x18\x02 \x01(\t\x12\x0f\n\x07\x61\x63tions\x18\x03 \x03(\t\x12\x10\n\x08services\x18\x04 \x03(\t\"P\n\x16WorkerRegisterResponse\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x10\n\x08workerId\x18\x02 \x01(\t\x12\x12\n\nworkerName\x18\x03 \x01(\t\"\xc1\x01\n\x0e\x41ssignedAction\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\r\n\x05jobId\x18\x02 \x01(\t\x12\x0f\n\x07jobName\x18\x03 \x01(\t\x12\x10\n\x08jobRunId\x18\x04 \x01(\t\x12\x0e\n\x06stepId\x18\x05 \x01(\t\x12\x11\n\tstepRunId\x18\x06 \x01(\t\x12\x10\n\x08\x61\x63tionId\x18\x07 \x01(\t\x12\x1f\n\nactionType\x18\x08 \x01(\x0e\x32\x0b.ActionType\x12\x15\n\ractionPayload\x18\t \x01(\t\"9\n\x13WorkerListenRequest\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x10\n\x08workerId\x18\x02 \x01(\t\">\n\x18WorkerUnsubscribeRequest\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x10\n\x08workerId\x18\x02 \x01(\t\"?\n\x19WorkerUnsubscribeResponse\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x10\n\x08workerId\x18\x02 \x01(\t\"\xf6\x01\n\x0b\x41\x63tionEvent\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x10\n\x08workerId\x18\x02 \x01(\t\x12\r\n\x05jobId\x18\x03 \x01(\t\x12\x10\n\x08jobRunId\x18\x04 \x01(\t\x12\x0e\n\x06stepId\x18\x05 \x01(\t\x12\x11\n\tstepRunId\x18\x06 \x01(\t\x12\x10\n\x08\x61\x63tionId\x18\x07 \x01(\t\x12\x32\n\x0e\x65ventTimestamp\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12#\n\teventType\x18\t \x01(\x0e\x32\x10.ActionEventType\x12\x14\n\x0c\x65ventPayload\x18\n \x01(\t\"9\n\x13\x41\x63tionEventResponse\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x10\n\x08workerId\x18\x02 \x01(\t*5\n\nActionType\x12\x12\n\x0eSTART_STEP_RUN\x10\x00\x12\x13\n\x0f\x43\x41NCEL_STEP_RUN\x10\x01*\x86\x01\n\x0f\x41\x63tionEventType\x12\x1b\n\x17STEP_EVENT_TYPE_UNKNOWN\x10\x00\x12\x1b\n\x17STEP_EVENT_TYPE_STARTED\x10\x01\x12\x1d\n\x19STEP_EVENT_TYPE_COMPLETED\x10\x02\x12\x1a\n\x16STEP_EVENT_TYPE_FAILED\x10\x03\x32\x81\x02\n\nDispatcher\x12=\n\x08Register\x12\x16.WorkerRegisterRequest\x1a\x17.WorkerRegisterResponse\"\x00\x12\x33\n\x06Listen\x12\x14.WorkerListenRequest\x1a\x0f.AssignedAction\"\x00\x30\x01\x12\x37\n\x0fSendActionEvent\x12\x0c.ActionEvent\x1a\x14.ActionEventResponse\"\x00\x12\x46\n\x0bUnsubscribe\x12\x19.WorkerUnsubscribeRequest\x1a\x1a.WorkerUnsubscribeResponse\"\x00\x42GZEgithub.com/hatchet-dev/hatchet/internal/services/dispatcher/contractsb\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10\x64ispatcher.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"N\n\x15WorkerRegisterRequest\x12\x12\n\nworkerName\x18\x01 \x01(\t\x12\x0f\n\x07\x61\x63tions\x18\x02 \x03(\t\x12\x10\n\x08services\x18\x03 \x03(\t\"P\n\x16WorkerRegisterResponse\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x10\n\x08workerId\x18\x02 \x01(\t\x12\x12\n\nworkerName\x18\x03 \x01(\t\"\xc1\x01\n\x0e\x41ssignedAction\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\r\n\x05jobId\x18\x02 \x01(\t\x12\x0f\n\x07jobName\x18\x03 \x01(\t\x12\x10\n\x08jobRunId\x18\x04 \x01(\t\x12\x0e\n\x06stepId\x18\x05 \x01(\t\x12\x11\n\tstepRunId\x18\x06 \x01(\t\x12\x10\n\x08\x61\x63tionId\x18\x07 \x01(\t\x12\x1f\n\nactionType\x18\x08 \x01(\x0e\x32\x0b.ActionType\x12\x15\n\ractionPayload\x18\t \x01(\t\"\'\n\x13WorkerListenRequest\x12\x10\n\x08workerId\x18\x01 \x01(\t\",\n\x18WorkerUnsubscribeRequest\x12\x10\n\x08workerId\x18\x01 \x01(\t\"?\n\x19WorkerUnsubscribeResponse\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x10\n\x08workerId\x18\x02 \x01(\t\"\xe4\x01\n\x0b\x41\x63tionEvent\x12\x10\n\x08workerId\x18\x01 \x01(\t\x12\r\n\x05jobId\x18\x02 \x01(\t\x12\x10\n\x08jobRunId\x18\x03 \x01(\t\x12\x0e\n\x06stepId\x18\x04 \x01(\t\x12\x11\n\tstepRunId\x18\x05 \x01(\t\x12\x10\n\x08\x61\x63tionId\x18\x06 \x01(\t\x12\x32\n\x0e\x65ventTimestamp\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12#\n\teventType\x18\x08 \x01(\x0e\x32\x10.ActionEventType\x12\x14\n\x0c\x65ventPayload\x18\t \x01(\t\"9\n\x13\x41\x63tionEventResponse\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x10\n\x08workerId\x18\x02 \x01(\t*5\n\nActionType\x12\x12\n\x0eSTART_STEP_RUN\x10\x00\x12\x13\n\x0f\x43\x41NCEL_STEP_RUN\x10\x01*\x86\x01\n\x0f\x41\x63tionEventType\x12\x1b\n\x17STEP_EVENT_TYPE_UNKNOWN\x10\x00\x12\x1b\n\x17STEP_EVENT_TYPE_STARTED\x10\x01\x12\x1d\n\x19STEP_EVENT_TYPE_COMPLETED\x10\x02\x12\x1a\n\x16STEP_EVENT_TYPE_FAILED\x10\x03\x32\x81\x02\n\nDispatcher\x12=\n\x08Register\x12\x16.WorkerRegisterRequest\x1a\x17.WorkerRegisterResponse\"\x00\x12\x33\n\x06Listen\x12\x14.WorkerListenRequest\x1a\x0f.AssignedAction\"\x00\x30\x01\x12\x37\n\x0fSendActionEvent\x12\x0c.ActionEvent\x1a\x14.ActionEventResponse\"\x00\x12\x46\n\x0bUnsubscribe\x12\x19.WorkerUnsubscribeRequest\x1a\x1a.WorkerUnsubscribeResponse\"\x00\x42GZEgithub.com/hatchet-dev/hatchet/internal/services/dispatcher/contractsb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
@@ -23,26 +23,26 @@ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'dispatcher_pb2', _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals['DESCRIPTOR']._options = None
|
||||
_globals['DESCRIPTOR']._serialized_options = b'ZEgithub.com/hatchet-dev/hatchet/internal/services/dispatcher/contracts'
|
||||
_globals['_ACTIONTYPE']._serialized_start=925
|
||||
_globals['_ACTIONTYPE']._serialized_end=978
|
||||
_globals['_ACTIONEVENTTYPE']._serialized_start=981
|
||||
_globals['_ACTIONEVENTTYPE']._serialized_end=1115
|
||||
_globals['_ACTIONTYPE']._serialized_start=853
|
||||
_globals['_ACTIONTYPE']._serialized_end=906
|
||||
_globals['_ACTIONEVENTTYPE']._serialized_start=909
|
||||
_globals['_ACTIONEVENTTYPE']._serialized_end=1043
|
||||
_globals['_WORKERREGISTERREQUEST']._serialized_start=53
|
||||
_globals['_WORKERREGISTERREQUEST']._serialized_end=149
|
||||
_globals['_WORKERREGISTERRESPONSE']._serialized_start=151
|
||||
_globals['_WORKERREGISTERRESPONSE']._serialized_end=231
|
||||
_globals['_ASSIGNEDACTION']._serialized_start=234
|
||||
_globals['_ASSIGNEDACTION']._serialized_end=427
|
||||
_globals['_WORKERLISTENREQUEST']._serialized_start=429
|
||||
_globals['_WORKERLISTENREQUEST']._serialized_end=486
|
||||
_globals['_WORKERUNSUBSCRIBEREQUEST']._serialized_start=488
|
||||
_globals['_WORKERUNSUBSCRIBEREQUEST']._serialized_end=550
|
||||
_globals['_WORKERUNSUBSCRIBERESPONSE']._serialized_start=552
|
||||
_globals['_WORKERUNSUBSCRIBERESPONSE']._serialized_end=615
|
||||
_globals['_ACTIONEVENT']._serialized_start=618
|
||||
_globals['_ACTIONEVENT']._serialized_end=864
|
||||
_globals['_ACTIONEVENTRESPONSE']._serialized_start=866
|
||||
_globals['_ACTIONEVENTRESPONSE']._serialized_end=923
|
||||
_globals['_DISPATCHER']._serialized_start=1118
|
||||
_globals['_DISPATCHER']._serialized_end=1375
|
||||
_globals['_WORKERREGISTERREQUEST']._serialized_end=131
|
||||
_globals['_WORKERREGISTERRESPONSE']._serialized_start=133
|
||||
_globals['_WORKERREGISTERRESPONSE']._serialized_end=213
|
||||
_globals['_ASSIGNEDACTION']._serialized_start=216
|
||||
_globals['_ASSIGNEDACTION']._serialized_end=409
|
||||
_globals['_WORKERLISTENREQUEST']._serialized_start=411
|
||||
_globals['_WORKERLISTENREQUEST']._serialized_end=450
|
||||
_globals['_WORKERUNSUBSCRIBEREQUEST']._serialized_start=452
|
||||
_globals['_WORKERUNSUBSCRIBEREQUEST']._serialized_end=496
|
||||
_globals['_WORKERUNSUBSCRIBERESPONSE']._serialized_start=498
|
||||
_globals['_WORKERUNSUBSCRIBERESPONSE']._serialized_end=561
|
||||
_globals['_ACTIONEVENT']._serialized_start=564
|
||||
_globals['_ACTIONEVENT']._serialized_end=792
|
||||
_globals['_ACTIONEVENTRESPONSE']._serialized_start=794
|
||||
_globals['_ACTIONEVENTRESPONSE']._serialized_end=851
|
||||
_globals['_DISPATCHER']._serialized_start=1046
|
||||
_globals['_DISPATCHER']._serialized_end=1303
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
@@ -26,16 +26,14 @@ STEP_EVENT_TYPE_COMPLETED: ActionEventType
|
||||
STEP_EVENT_TYPE_FAILED: ActionEventType
|
||||
|
||||
class WorkerRegisterRequest(_message.Message):
|
||||
__slots__ = ("tenantId", "workerName", "actions", "services")
|
||||
TENANTID_FIELD_NUMBER: _ClassVar[int]
|
||||
__slots__ = ("workerName", "actions", "services")
|
||||
WORKERNAME_FIELD_NUMBER: _ClassVar[int]
|
||||
ACTIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
SERVICES_FIELD_NUMBER: _ClassVar[int]
|
||||
tenantId: str
|
||||
workerName: str
|
||||
actions: _containers.RepeatedScalarFieldContainer[str]
|
||||
services: _containers.RepeatedScalarFieldContainer[str]
|
||||
def __init__(self, tenantId: _Optional[str] = ..., workerName: _Optional[str] = ..., actions: _Optional[_Iterable[str]] = ..., services: _Optional[_Iterable[str]] = ...) -> None: ...
|
||||
def __init__(self, workerName: _Optional[str] = ..., actions: _Optional[_Iterable[str]] = ..., services: _Optional[_Iterable[str]] = ...) -> None: ...
|
||||
|
||||
class WorkerRegisterResponse(_message.Message):
|
||||
__slots__ = ("tenantId", "workerId", "workerName")
|
||||
@@ -70,20 +68,16 @@ class AssignedAction(_message.Message):
|
||||
def __init__(self, tenantId: _Optional[str] = ..., jobId: _Optional[str] = ..., jobName: _Optional[str] = ..., jobRunId: _Optional[str] = ..., stepId: _Optional[str] = ..., stepRunId: _Optional[str] = ..., actionId: _Optional[str] = ..., actionType: _Optional[_Union[ActionType, str]] = ..., actionPayload: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class WorkerListenRequest(_message.Message):
|
||||
__slots__ = ("tenantId", "workerId")
|
||||
TENANTID_FIELD_NUMBER: _ClassVar[int]
|
||||
__slots__ = ("workerId",)
|
||||
WORKERID_FIELD_NUMBER: _ClassVar[int]
|
||||
tenantId: str
|
||||
workerId: str
|
||||
def __init__(self, tenantId: _Optional[str] = ..., workerId: _Optional[str] = ...) -> None: ...
|
||||
def __init__(self, workerId: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class WorkerUnsubscribeRequest(_message.Message):
|
||||
__slots__ = ("tenantId", "workerId")
|
||||
TENANTID_FIELD_NUMBER: _ClassVar[int]
|
||||
__slots__ = ("workerId",)
|
||||
WORKERID_FIELD_NUMBER: _ClassVar[int]
|
||||
tenantId: str
|
||||
workerId: str
|
||||
def __init__(self, tenantId: _Optional[str] = ..., workerId: _Optional[str] = ...) -> None: ...
|
||||
def __init__(self, workerId: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class WorkerUnsubscribeResponse(_message.Message):
|
||||
__slots__ = ("tenantId", "workerId")
|
||||
@@ -94,8 +88,7 @@ class WorkerUnsubscribeResponse(_message.Message):
|
||||
def __init__(self, tenantId: _Optional[str] = ..., workerId: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class ActionEvent(_message.Message):
|
||||
__slots__ = ("tenantId", "workerId", "jobId", "jobRunId", "stepId", "stepRunId", "actionId", "eventTimestamp", "eventType", "eventPayload")
|
||||
TENANTID_FIELD_NUMBER: _ClassVar[int]
|
||||
__slots__ = ("workerId", "jobId", "jobRunId", "stepId", "stepRunId", "actionId", "eventTimestamp", "eventType", "eventPayload")
|
||||
WORKERID_FIELD_NUMBER: _ClassVar[int]
|
||||
JOBID_FIELD_NUMBER: _ClassVar[int]
|
||||
JOBRUNID_FIELD_NUMBER: _ClassVar[int]
|
||||
@@ -105,7 +98,6 @@ class ActionEvent(_message.Message):
|
||||
EVENTTIMESTAMP_FIELD_NUMBER: _ClassVar[int]
|
||||
EVENTTYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
EVENTPAYLOAD_FIELD_NUMBER: _ClassVar[int]
|
||||
tenantId: str
|
||||
workerId: str
|
||||
jobId: str
|
||||
jobRunId: str
|
||||
@@ -115,7 +107,7 @@ class ActionEvent(_message.Message):
|
||||
eventTimestamp: _timestamp_pb2.Timestamp
|
||||
eventType: ActionEventType
|
||||
eventPayload: str
|
||||
def __init__(self, tenantId: _Optional[str] = ..., workerId: _Optional[str] = ..., jobId: _Optional[str] = ..., jobRunId: _Optional[str] = ..., stepId: _Optional[str] = ..., stepRunId: _Optional[str] = ..., actionId: _Optional[str] = ..., eventTimestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., eventType: _Optional[_Union[ActionEventType, str]] = ..., eventPayload: _Optional[str] = ...) -> None: ...
|
||||
def __init__(self, workerId: _Optional[str] = ..., jobId: _Optional[str] = ..., jobRunId: _Optional[str] = ..., stepId: _Optional[str] = ..., stepRunId: _Optional[str] = ..., actionId: _Optional[str] = ..., eventTimestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ..., eventType: _Optional[_Union[ActionEventType, str]] = ..., eventPayload: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class ActionEventResponse(_message.Message):
|
||||
__slots__ = ("tenantId", "workerId")
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
import grpc
|
||||
|
||||
# import dispatcher_pb2 as dispatcher__pb2
|
||||
from . import dispatcher_pb2 as dispatcher__pb2
|
||||
|
||||
class DispatcherStub(object):
|
||||
|
||||
@@ -15,7 +15,7 @@ _sym_db = _symbol_database.Default()
|
||||
from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x65vents.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"|\n\x05\x45vent\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x0f\n\x07\x65ventId\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\t\x12\x0f\n\x07payload\x18\x04 \x01(\t\x12\x32\n\x0e\x65ventTimestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"v\n\x10PushEventRequest\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\t\x12\x0f\n\x07payload\x18\x03 \x01(\t\x12\x32\n\x0e\x65ventTimestamp\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"A\n\x10ListEventRequest\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x0e\n\x06offset\x18\x02 \x01(\x05\x12\x0b\n\x03key\x18\x03 \x01(\t\"+\n\x11ListEventResponse\x12\x16\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x06.Event\"7\n\x12ReplayEventRequest\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x0f\n\x07\x65ventId\x18\x02 \x01(\t2\x99\x01\n\rEventsService\x12#\n\x04Push\x12\x11.PushEventRequest\x1a\x06.Event\"\x00\x12/\n\x04List\x12\x11.ListEventRequest\x1a\x12.ListEventResponse\"\x00\x12\x32\n\x11ReplaySingleEvent\x12\x13.ReplayEventRequest\x1a\x06.Event\"\x00\x42GZEgithub.com/hatchet-dev/hatchet/internal/services/dispatcher/contractsb\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x65vents.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"|\n\x05\x45vent\x12\x10\n\x08tenantId\x18\x01 \x01(\t\x12\x0f\n\x07\x65ventId\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\t\x12\x0f\n\x07payload\x18\x04 \x01(\t\x12\x32\n\x0e\x65ventTimestamp\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"d\n\x10PushEventRequest\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x0f\n\x07payload\x18\x02 \x01(\t\x12\x32\n\x0e\x65ventTimestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"/\n\x10ListEventRequest\x12\x0e\n\x06offset\x18\x01 \x01(\x05\x12\x0b\n\x03key\x18\x02 \x01(\t\"+\n\x11ListEventResponse\x12\x16\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x06.Event\"%\n\x12ReplayEventRequest\x12\x0f\n\x07\x65ventId\x18\x01 \x01(\t2\x99\x01\n\rEventsService\x12#\n\x04Push\x12\x11.PushEventRequest\x1a\x06.Event\"\x00\x12/\n\x04List\x12\x11.ListEventRequest\x1a\x12.ListEventResponse\"\x00\x12\x32\n\x11ReplaySingleEvent\x12\x13.ReplayEventRequest\x1a\x06.Event\"\x00\x42GZEgithub.com/hatchet-dev/hatchet/internal/services/dispatcher/contractsb\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
@@ -26,13 +26,13 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals['_EVENT']._serialized_start=49
|
||||
_globals['_EVENT']._serialized_end=173
|
||||
_globals['_PUSHEVENTREQUEST']._serialized_start=175
|
||||
_globals['_PUSHEVENTREQUEST']._serialized_end=293
|
||||
_globals['_LISTEVENTREQUEST']._serialized_start=295
|
||||
_globals['_LISTEVENTREQUEST']._serialized_end=360
|
||||
_globals['_LISTEVENTRESPONSE']._serialized_start=362
|
||||
_globals['_LISTEVENTRESPONSE']._serialized_end=405
|
||||
_globals['_REPLAYEVENTREQUEST']._serialized_start=407
|
||||
_globals['_REPLAYEVENTREQUEST']._serialized_end=462
|
||||
_globals['_EVENTSSERVICE']._serialized_start=465
|
||||
_globals['_EVENTSSERVICE']._serialized_end=618
|
||||
_globals['_PUSHEVENTREQUEST']._serialized_end=275
|
||||
_globals['_LISTEVENTREQUEST']._serialized_start=277
|
||||
_globals['_LISTEVENTREQUEST']._serialized_end=324
|
||||
_globals['_LISTEVENTRESPONSE']._serialized_start=326
|
||||
_globals['_LISTEVENTRESPONSE']._serialized_end=369
|
||||
_globals['_REPLAYEVENTREQUEST']._serialized_start=371
|
||||
_globals['_REPLAYEVENTREQUEST']._serialized_end=408
|
||||
_globals['_EVENTSSERVICE']._serialized_start=411
|
||||
_globals['_EVENTSSERVICE']._serialized_end=564
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
@@ -21,26 +21,22 @@ class Event(_message.Message):
|
||||
def __init__(self, tenantId: _Optional[str] = ..., eventId: _Optional[str] = ..., key: _Optional[str] = ..., payload: _Optional[str] = ..., eventTimestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
|
||||
|
||||
class PushEventRequest(_message.Message):
|
||||
__slots__ = ("tenantId", "key", "payload", "eventTimestamp")
|
||||
TENANTID_FIELD_NUMBER: _ClassVar[int]
|
||||
__slots__ = ("key", "payload", "eventTimestamp")
|
||||
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||
PAYLOAD_FIELD_NUMBER: _ClassVar[int]
|
||||
EVENTTIMESTAMP_FIELD_NUMBER: _ClassVar[int]
|
||||
tenantId: str
|
||||
key: str
|
||||
payload: str
|
||||
eventTimestamp: _timestamp_pb2.Timestamp
|
||||
def __init__(self, tenantId: _Optional[str] = ..., key: _Optional[str] = ..., payload: _Optional[str] = ..., eventTimestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
|
||||
def __init__(self, key: _Optional[str] = ..., payload: _Optional[str] = ..., eventTimestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...) -> None: ...
|
||||
|
||||
class ListEventRequest(_message.Message):
|
||||
__slots__ = ("tenantId", "offset", "key")
|
||||
TENANTID_FIELD_NUMBER: _ClassVar[int]
|
||||
__slots__ = ("offset", "key")
|
||||
OFFSET_FIELD_NUMBER: _ClassVar[int]
|
||||
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||
tenantId: str
|
||||
offset: int
|
||||
key: str
|
||||
def __init__(self, tenantId: _Optional[str] = ..., offset: _Optional[int] = ..., key: _Optional[str] = ...) -> None: ...
|
||||
def __init__(self, offset: _Optional[int] = ..., key: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class ListEventResponse(_message.Message):
|
||||
__slots__ = ("events",)
|
||||
@@ -49,9 +45,7 @@ class ListEventResponse(_message.Message):
|
||||
def __init__(self, events: _Optional[_Iterable[_Union[Event, _Mapping]]] = ...) -> None: ...
|
||||
|
||||
class ReplayEventRequest(_message.Message):
|
||||
__slots__ = ("tenantId", "eventId")
|
||||
TENANTID_FIELD_NUMBER: _ClassVar[int]
|
||||
__slots__ = ("eventId",)
|
||||
EVENTID_FIELD_NUMBER: _ClassVar[int]
|
||||
tenantId: str
|
||||
eventId: str
|
||||
def __init__(self, tenantId: _Optional[str] = ..., eventId: _Optional[str] = ...) -> None: ...
|
||||
def __init__(self, eventId: _Optional[str] = ...) -> None: ...
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"""Client and server classes corresponding to protobuf-defined services."""
|
||||
import grpc
|
||||
|
||||
# import events_pb2 as events__pb2
|
||||
from . import events_pb2 as events__pb2
|
||||
|
||||
class EventsServiceStub(object):
|
||||
|
||||
@@ -3,17 +3,19 @@ import yaml
|
||||
from typing import Any, Optional, Dict
|
||||
|
||||
class ClientTLSConfig:
|
||||
def __init__(self, cert_file: str, key_file: str, ca_file: str, server_name: str):
|
||||
def __init__(self, tls_strategy: str, cert_file: str, key_file: str, ca_file: str, server_name: str):
|
||||
self.tls_strategy = tls_strategy
|
||||
self.cert_file = cert_file
|
||||
self.key_file = key_file
|
||||
self.ca_file = ca_file
|
||||
self.server_name = server_name
|
||||
|
||||
class ClientConfig:
|
||||
def __init__(self, tenant_id: str, tls_config: ClientTLSConfig, host_port: str="localhost:7070"):
|
||||
def __init__(self, tenant_id: str, tls_config: ClientTLSConfig, token: str, host_port: str="localhost:7070"):
|
||||
self.tenant_id = tenant_id
|
||||
self.tls_config = tls_config
|
||||
self.host_port = host_port
|
||||
self.token = token
|
||||
|
||||
class ConfigLoader:
|
||||
def __init__(self, directory: str):
|
||||
@@ -30,20 +32,31 @@ class ConfigLoader:
|
||||
if os.path.exists(config_file_path):
|
||||
with open(config_file_path, 'r') as file:
|
||||
config_data = yaml.safe_load(file)
|
||||
|
||||
tls_config = self._load_tls_config(config_data['tls'])
|
||||
|
||||
tenant_id = config_data['tenantId'] if 'tenantId' in config_data else self._get_env_var('HATCHET_CLIENT_TENANT_ID')
|
||||
host_port = config_data['hostPort'] if 'hostPort' in config_data else self._get_env_var('HATCHET_CLIENT_HOST_PORT')
|
||||
token = config_data['token'] if 'token' in config_data else self._get_env_var('HATCHET_CLIENT_TOKEN')
|
||||
tls_config = self._load_tls_config(config_data['tls'], host_port)
|
||||
|
||||
return ClientConfig(tenant_id, tls_config, host_port)
|
||||
return ClientConfig(tenant_id, tls_config, token, host_port)
|
||||
|
||||
def _load_tls_config(self, tls_data: Dict, host_port) -> ClientTLSConfig:
|
||||
tls_strategy = tls_data['tlsStrategy'] if 'tlsStrategy' in tls_data else self._get_env_var('HATCHET_CLIENT_TLS_STRATEGY')
|
||||
|
||||
if not tls_strategy:
|
||||
tls_strategy = 'tls'
|
||||
|
||||
def _load_tls_config(self, tls_data: Dict) -> ClientTLSConfig:
|
||||
cert_file = tls_data['tlsCertFile'] if 'tlsCertFile' in tls_data else self._get_env_var('HATCHET_CLIENT_TLS_CERT_FILE')
|
||||
key_file = tls_data['tlsKeyFile'] if 'tlsKeyFile' in tls_data else self._get_env_var('HATCHET_CLIENT_TLS_KEY_FILE')
|
||||
ca_file = tls_data['tlsRootCAFile'] if 'tlsRootCAFile' in tls_data else self._get_env_var('HATCHET_CLIENT_TLS_ROOT_CA_FILE')
|
||||
|
||||
server_name = tls_data['tlsServerName'] if 'tlsServerName' in tls_data else self._get_env_var('HATCHET_CLIENT_TLS_SERVER_NAME')
|
||||
|
||||
return ClientTLSConfig(cert_file, key_file, ca_file, server_name)
|
||||
# if server_name is not set, use the host from the host_port
|
||||
if not server_name:
|
||||
server_name = host_port.split(':')[0]
|
||||
|
||||
return ClientTLSConfig(tls_strategy, cert_file, key_file, ca_file, server_name)
|
||||
|
||||
@staticmethod
|
||||
def _get_env_var(env_var: str, default: Optional[str] = None) -> str:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user