feat(host): make runner.environment configurable, github-hosted by default
- commit
- 61fc6ee26cf05e05562d9c4ab0483c266c5a3c11
- author
- brice · · 2026-10-12 22:44 UTC
- parent
- 81b458d
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
6 files · +54 -7
M README.md +1 -0
| @@ -94,6 +94,7 @@ the host process; the sandbox receives the workflow and its contexts only. | |||
| 94 | 94 | | `ERMITE_RUNNER_URL` | base URL of ermite, as in a browser (the runner adds `/-/api` itself) | | |
| 95 | 95 | | `ERMITE_RUNNER_NAME` | runner name (default: the host name) | | |
| 96 | 96 | | `ERMITE_RUNNER_LABELS` | extra labels, comma separated (`ubuntu-latest,ubuntu-24.04`) | | |
| 97 | + | | `ERMITE_RUNNER_ENVIRONMENT` | `github-hosted` (default) or `self-hosted`: the `runner.environment` value the jobs see. ermite's runners stand in for GitHub-hosted ones, so workflows written for github.com (`runner.environment == 'github-hosted'`) behave the same; `self-hosted` also makes "Set up job" print the runner and machine name, as GitHub does for self-hosted runners | | |
| 97 | 98 | | `ERMITE_RUNNER_REGISTER_TOKEN` | token for `register` (see above) | | |
| 98 | 99 | | `ERMITE_RUNNER_INSECURE_HTTP` | `1` allows a non-loopback `http://` URL (tests only) | | |
| 99 | 100 | | `ERMITE_RUNNER_LOG_LEVEL` | `debug`, `info` (default), `warn`, `error` | | |
| @@ -94,6 +94,7 @@ the host process; the sandbox receives the workflow and its contexts only. | |||||
| 94 | | `ERMITE_RUNNER_URL` | base URL of ermite, as in a browser (the runner adds `/-/api` itself) | | 94 | | `ERMITE_RUNNER_URL` | base URL of ermite, as in a browser (the runner adds `/-/api` itself) | | ||
| 95 | | `ERMITE_RUNNER_NAME` | runner name (default: the host name) | | 95 | | `ERMITE_RUNNER_NAME` | runner name (default: the host name) | | ||
| 96 | | `ERMITE_RUNNER_LABELS` | extra labels, comma separated (`ubuntu-latest,ubuntu-24.04`) | | 96 | | `ERMITE_RUNNER_LABELS` | extra labels, comma separated (`ubuntu-latest,ubuntu-24.04`) | | ||
| 97 | + | | `ERMITE_RUNNER_ENVIRONMENT` | `github-hosted` (default) or `self-hosted`: the `runner.environment` value the jobs see. ermite's runners stand in for GitHub-hosted ones, so workflows written for github.com (`runner.environment == 'github-hosted'`) behave the same; `self-hosted` also makes "Set up job" print the runner and machine name, as GitHub does for self-hosted runners | | |||
| 97 | | `ERMITE_RUNNER_REGISTER_TOKEN` | token for `register` (see above) | | 98 | | `ERMITE_RUNNER_REGISTER_TOKEN` | token for `register` (see above) | | ||
| 98 | | `ERMITE_RUNNER_INSECURE_HTTP` | `1` allows a non-loopback `http://` URL (tests only) | | 99 | | `ERMITE_RUNNER_INSECURE_HTTP` | `1` allows a non-loopback `http://` URL (tests only) | | ||
| 99 | | `ERMITE_RUNNER_LOG_LEVEL` | `debug`, `info` (default), `warn`, `error` | | 100 | | `ERMITE_RUNNER_LOG_LEVEL` | `debug`, `info` (default), `warn`, `error` | | ||
M internal/execstream/exec.proto +1 -1
| @@ -57,7 +57,7 @@ message JobSpec { | |||
| 57 | 57 | int32 timeout_minutes = 7; | |
| 58 | 58 | string runner_name = 8; | |
| 59 | 59 | string runner_version = 9; | |
| 60 | - | // runner_environment is the runner.environment value ("self-hosted"). | |
| 60 | + | // runner_environment is the runner.environment value ("github-hosted" or "self-hosted"). | |
| 61 | 61 | string runner_environment = 10; | |
| 62 | 62 | bool debug = 11; // ACTIONS_STEP_DEBUG | |
| 63 | 63 | // deadline_ms is what is left of the job timeout when the host sends this | |
| @@ -57,7 +57,7 @@ message JobSpec { | |||||
| 57 | int32 timeout_minutes = 7; | 57 | int32 timeout_minutes = 7; | ||
| 58 | string runner_name = 8; | 58 | string runner_name = 8; | ||
| 59 | string runner_version = 9; | 59 | string runner_version = 9; | ||
| 60 | - | // runner_environment is the runner.environment value ("self-hosted"). | 60 | + | // runner_environment is the runner.environment value ("github-hosted" or "self-hosted"). |
| 61 | string runner_environment = 10; | 61 | string runner_environment = 10; | ||
| 62 | bool debug = 11; // ACTIONS_STEP_DEBUG | 62 | bool debug = 11; // ACTIONS_STEP_DEBUG | ||
| 63 | // deadline_ms is what is left of the job timeout when the host sends this | 63 | // deadline_ms is what is left of the job timeout when the host sends this | ||
M internal/execstream/execpb/exec.pb.go +1 -1
| @@ -522,7 +522,7 @@ type JobSpec struct { | |||
| 522 | 522 | TimeoutMinutes int32 `protobuf:"varint,7,opt,name=timeout_minutes,json=timeoutMinutes,proto3" json:"timeout_minutes,omitempty"` | |
| 523 | 523 | RunnerName string `protobuf:"bytes,8,opt,name=runner_name,json=runnerName,proto3" json:"runner_name,omitempty"` | |
| 524 | 524 | RunnerVersion string `protobuf:"bytes,9,opt,name=runner_version,json=runnerVersion,proto3" json:"runner_version,omitempty"` | |
| 525 | - | // runner_environment is the runner.environment value ("self-hosted"). | |
| 525 | + | // runner_environment is the runner.environment value ("github-hosted" or "self-hosted"). | |
| 526 | 526 | RunnerEnvironment string `protobuf:"bytes,10,opt,name=runner_environment,json=runnerEnvironment,proto3" json:"runner_environment,omitempty"` | |
| 527 | 527 | Debug bool `protobuf:"varint,11,opt,name=debug,proto3" json:"debug,omitempty"` // ACTIONS_STEP_DEBUG | |
| 528 | 528 | // deadline_ms is what is left of the job timeout when the host sends this | |
| @@ -522,7 +522,7 @@ type JobSpec struct { | |||||
| 522 | TimeoutMinutes int32 `protobuf:"varint,7,opt,name=timeout_minutes,json=timeoutMinutes,proto3" json:"timeout_minutes,omitempty"` | 522 | TimeoutMinutes int32 `protobuf:"varint,7,opt,name=timeout_minutes,json=timeoutMinutes,proto3" json:"timeout_minutes,omitempty"` | ||
| 523 | RunnerName string `protobuf:"bytes,8,opt,name=runner_name,json=runnerName,proto3" json:"runner_name,omitempty"` | 523 | RunnerName string `protobuf:"bytes,8,opt,name=runner_name,json=runnerName,proto3" json:"runner_name,omitempty"` | ||
| 524 | RunnerVersion string `protobuf:"bytes,9,opt,name=runner_version,json=runnerVersion,proto3" json:"runner_version,omitempty"` | 524 | RunnerVersion string `protobuf:"bytes,9,opt,name=runner_version,json=runnerVersion,proto3" json:"runner_version,omitempty"` | ||
| 525 | - | // runner_environment is the runner.environment value ("self-hosted"). | 525 | + | // runner_environment is the runner.environment value ("github-hosted" or "self-hosted"). |
| 526 | RunnerEnvironment string `protobuf:"bytes,10,opt,name=runner_environment,json=runnerEnvironment,proto3" json:"runner_environment,omitempty"` | 526 | RunnerEnvironment string `protobuf:"bytes,10,opt,name=runner_environment,json=runnerEnvironment,proto3" json:"runner_environment,omitempty"` | ||
| 527 | Debug bool `protobuf:"varint,11,opt,name=debug,proto3" json:"debug,omitempty"` // ACTIONS_STEP_DEBUG | 527 | Debug bool `protobuf:"varint,11,opt,name=debug,proto3" json:"debug,omitempty"` // ACTIONS_STEP_DEBUG | ||
| 528 | // deadline_ms is what is left of the job timeout when the host sends this | 528 | // deadline_ms is what is left of the job timeout when the host sends this | ||
M internal/host/config.go +37 -3
| @@ -20,15 +20,24 @@ import ( | |||
| 20 | 20 | // (ERMITE_RUNNER_ISOLATION, _CAPACITY, _IMAGE, _JOB_*) are read by package | |
| 21 | 21 | // sandbox. | |
| 22 | 22 | const ( | |
| 23 | - | EnvURL = "ERMITE_RUNNER_URL" | |
| 24 | - | EnvName = "ERMITE_RUNNER_NAME" | |
| 25 | - | EnvLabels = "ERMITE_RUNNER_LABELS" | |
| 23 | + | EnvURL = "ERMITE_RUNNER_URL" | |
| 24 | + | EnvName = "ERMITE_RUNNER_NAME" | |
| 25 | + | EnvLabels = "ERMITE_RUNNER_LABELS" | |
| 26 | + | // EnvEnvironment is the runner.environment value that jobs see: see | |
| 27 | + | // Config.Environment. | |
| 28 | + | EnvEnvironment = "ERMITE_RUNNER_ENVIRONMENT" | |
| 26 | 29 | EnvRegisterToken = "ERMITE_RUNNER_REGISTER_TOKEN" | |
| 27 | 30 | // EnvInsecureHTTP allows a plain http server URL that is not loopback. The | |
| 28 | 31 | // runner token and the job tokens then travel in clear: tests only. | |
| 29 | 32 | EnvInsecureHTTP = "ERMITE_RUNNER_INSECURE_HTTP" | |
| 30 | 33 | ) | |
| 31 | 34 | ||
| 35 | + | // The values of Config.Environment, as GitHub spells them. | |
| 36 | + | const ( | |
| 37 | + | EnvGitHubHosted = "github-hosted" | |
| 38 | + | EnvSelfHosted = "self-hosted" | |
| 39 | + | ) | |
| 40 | + | ||
| 32 | 41 | // Config is the host part of the runner configuration. | |
| 33 | 42 | type Config struct { | |
| 34 | 43 | // URL is the base URL of the ermite server. | |
| @@ -43,6 +52,14 @@ type Config struct { | |||
| 43 | 52 | Capacity int | |
| 44 | 53 | // Version is the version of the runner binary. | |
| 45 | 54 | Version string | |
| 55 | + | // Environment is the "runner.environment" value of the jobs and what decides | |
| 56 | + | // whether "Set up job" prints the runner and machine name: EnvGitHubHosted | |
| 57 | + | // (the default) or EnvSelfHosted. The runners of ermite stand in for the | |
| 58 | + | // GitHub-hosted ones: workflows written for github.com test | |
| 59 | + | // runner.environment == 'github-hosted' and the recordings of github.com | |
| 60 | + | // (ermite-conformance) carry that value, so it is the default; an operator | |
| 61 | + | // who wants jobs to see a self-hosted runner sets ERMITE_RUNNER_ENVIRONMENT. | |
| 62 | + | Environment string | |
| 46 | 63 | // InsecureHTTP allows a non-loopback http URL (ERMITE_RUNNER_INSECURE_HTTP=1). | |
| 47 | 64 | InsecureHTTP bool | |
| 48 | 65 | } | |
| @@ -55,6 +72,15 @@ func (c Config) Client(url, token string) ermiteconnect.RunnerServiceClient { | |||
| 55 | 72 | return NewClient(url, token, http.DefaultTransport) | |
| 56 | 73 | } | |
| 57 | 74 | ||
| 75 | + | // environment is Environment, the default when a Config was built without | |
| 76 | + | // LoadConfig. | |
| 77 | + | func (c Config) environment() string { | |
| 78 | + | if c.Environment == "" { | |
| 79 | + | return EnvGitHubHosted | |
| 80 | + | } | |
| 81 | + | return c.Environment | |
| 82 | + | } | |
| 83 | + | ||
| 58 | 84 | var nameRe = regexp.MustCompile(`^[A-Za-z0-9._-]{1,64}$`) | |
| 59 | 85 | ||
| 60 | 86 | // LoadConfig reads the host settings. hostname is the default runner name. | |
| @@ -65,6 +91,14 @@ func LoadConfig(getenv func(string) string, hostname, stateDir string, capacity | |||
| 65 | 91 | if c.Name == "" { | |
| 66 | 92 | c.Name = sanitizeName(hostname) | |
| 67 | 93 | } | |
| 94 | + | switch v := strings.ToLower(strings.TrimSpace(getenv(EnvEnvironment))); v { | |
| 95 | + | case "": | |
| 96 | + | c.Environment = EnvGitHubHosted | |
| 97 | + | case EnvGitHubHosted, EnvSelfHosted: | |
| 98 | + | c.Environment = v | |
| 99 | + | default: | |
| 100 | + | return c, fmt.Errorf("%s: %q is not %s or %s", EnvEnvironment, getenv(EnvEnvironment), EnvGitHubHosted, EnvSelfHosted) | |
| 101 | + | } | |
| 68 | 102 | switch strings.ToLower(strings.TrimSpace(getenv(EnvInsecureHTTP))) { | |
| 69 | 103 | case "", "0", "false", "no": | |
| 70 | 104 | case "1", "true", "yes": | |
| @@ -20,15 +20,24 @@ import ( | |||||
| 20 | // (ERMITE_RUNNER_ISOLATION, _CAPACITY, _IMAGE, _JOB_*) are read by package | 20 | // (ERMITE_RUNNER_ISOLATION, _CAPACITY, _IMAGE, _JOB_*) are read by package | ||
| 21 | // sandbox. | 21 | // sandbox. | ||
| 22 | const ( | 22 | const ( | ||
| 23 | - | EnvURL = "ERMITE_RUNNER_URL" | 23 | + | EnvURL = "ERMITE_RUNNER_URL" |
| 24 | - | EnvName = "ERMITE_RUNNER_NAME" | 24 | + | EnvName = "ERMITE_RUNNER_NAME" |
| 25 | - | EnvLabels = "ERMITE_RUNNER_LABELS" | 25 | + | EnvLabels = "ERMITE_RUNNER_LABELS" |
| 26 | + | // EnvEnvironment is the runner.environment value that jobs see: see | |||
| 27 | + | // Config.Environment. | |||
| 28 | + | EnvEnvironment = "ERMITE_RUNNER_ENVIRONMENT" | |||
| 26 | EnvRegisterToken = "ERMITE_RUNNER_REGISTER_TOKEN" | 29 | EnvRegisterToken = "ERMITE_RUNNER_REGISTER_TOKEN" | ||
| 27 | // EnvInsecureHTTP allows a plain http server URL that is not loopback. The | 30 | // EnvInsecureHTTP allows a plain http server URL that is not loopback. The | ||
| 28 | // runner token and the job tokens then travel in clear: tests only. | 31 | // runner token and the job tokens then travel in clear: tests only. | ||
| 29 | EnvInsecureHTTP = "ERMITE_RUNNER_INSECURE_HTTP" | 32 | EnvInsecureHTTP = "ERMITE_RUNNER_INSECURE_HTTP" | ||
| 30 | ) | 33 | ) | ||
| 31 | 34 | ||||
| 35 | + | // The values of Config.Environment, as GitHub spells them. | |||
| 36 | + | const ( | |||
| 37 | + | EnvGitHubHosted = "github-hosted" | |||
| 38 | + | EnvSelfHosted = "self-hosted" | |||
| 39 | + | ) | |||
| 40 | + | ||||
| 32 | // Config is the host part of the runner configuration. | 41 | // Config is the host part of the runner configuration. | ||
| 33 | type Config struct { | 42 | type Config struct { | ||
| 34 | // URL is the base URL of the ermite server. | 43 | // URL is the base URL of the ermite server. | ||
| @@ -43,6 +52,14 @@ type Config struct { | |||||
| 43 | Capacity int | 52 | Capacity int | ||
| 44 | // Version is the version of the runner binary. | 53 | // Version is the version of the runner binary. | ||
| 45 | Version string | 54 | Version string | ||
| 55 | + | // Environment is the "runner.environment" value of the jobs and what decides | |||
| 56 | + | // whether "Set up job" prints the runner and machine name: EnvGitHubHosted | |||
| 57 | + | // (the default) or EnvSelfHosted. The runners of ermite stand in for the | |||
| 58 | + | // GitHub-hosted ones: workflows written for github.com test | |||
| 59 | + | // runner.environment == 'github-hosted' and the recordings of github.com | |||
| 60 | + | // (ermite-conformance) carry that value, so it is the default; an operator | |||
| 61 | + | // who wants jobs to see a self-hosted runner sets ERMITE_RUNNER_ENVIRONMENT. | |||
| 62 | + | Environment string | |||
| 46 | // InsecureHTTP allows a non-loopback http URL (ERMITE_RUNNER_INSECURE_HTTP=1). | 63 | // InsecureHTTP allows a non-loopback http URL (ERMITE_RUNNER_INSECURE_HTTP=1). | ||
| 47 | InsecureHTTP bool | 64 | InsecureHTTP bool | ||
| 48 | } | 65 | } | ||
| @@ -55,6 +72,15 @@ func (c Config) Client(url, token string) ermiteconnect.RunnerServiceClient { | |||||
| 55 | return NewClient(url, token, http.DefaultTransport) | 72 | return NewClient(url, token, http.DefaultTransport) | ||
| 56 | } | 73 | } | ||
| 57 | 74 | ||||
| 75 | + | // environment is Environment, the default when a Config was built without | |||
| 76 | + | // LoadConfig. | |||
| 77 | + | func (c Config) environment() string { | |||
| 78 | + | if c.Environment == "" { | |||
| 79 | + | return EnvGitHubHosted | |||
| 80 | + | } | |||
| 81 | + | return c.Environment | |||
| 82 | + | } | |||
| 83 | + | ||||
| 58 | var nameRe = regexp.MustCompile(`^[A-Za-z0-9._-]{1,64}$`) | 84 | var nameRe = regexp.MustCompile(`^[A-Za-z0-9._-]{1,64}$`) | ||
| 59 | 85 | ||||
| 60 | // LoadConfig reads the host settings. hostname is the default runner name. | 86 | // LoadConfig reads the host settings. hostname is the default runner name. | ||
| @@ -65,6 +91,14 @@ func LoadConfig(getenv func(string) string, hostname, stateDir string, capacity | |||||
| 65 | if c.Name == "" { | 91 | if c.Name == "" { | ||
| 66 | c.Name = sanitizeName(hostname) | 92 | c.Name = sanitizeName(hostname) | ||
| 67 | } | 93 | } | ||
| 94 | + | switch v := strings.ToLower(strings.TrimSpace(getenv(EnvEnvironment))); v { | |||
| 95 | + | case "": | |||
| 96 | + | c.Environment = EnvGitHubHosted | |||
| 97 | + | case EnvGitHubHosted, EnvSelfHosted: | |||
| 98 | + | c.Environment = v | |||
| 99 | + | default: | |||
| 100 | + | return c, fmt.Errorf("%s: %q is not %s or %s", EnvEnvironment, getenv(EnvEnvironment), EnvGitHubHosted, EnvSelfHosted) | |||
| 101 | + | } | |||
| 68 | switch strings.ToLower(strings.TrimSpace(getenv(EnvInsecureHTTP))) { | 102 | switch strings.ToLower(strings.TrimSpace(getenv(EnvInsecureHTTP))) { | ||
| 69 | case "", "0", "false", "no": | 103 | case "", "0", "false", "no": | ||
| 70 | case "1", "true", "yes": | 104 | case "1", "true", "yes": | ||
M internal/host/job.go +1 -1
| @@ -634,7 +634,7 @@ func (j *jobRun) drive(conn sandbox.Conn, rt *Runner) (*execpb.Exit, error) { | |||
| 634 | 634 | WorkflowPath: j.job.WorkflowPath, WorkflowYaml: j.job.WorkflowYaml, JobKey: j.job.JobKey, | |
| 635 | 635 | Matrix: j.job.Matrix, Contexts: j.job.Contexts, Repo: j.job.Repo, TimeoutMinutes: int32(j.timeoutMinutes()), | |
| 636 | 636 | DeadlineMs: max(1, time.Until(j.deadline()).Milliseconds()), | |
| 637 | - | RunnerName: rt.Cfg.Name, RunnerVersion: rt.Cfg.Version, RunnerEnvironment: "self-hosted", | |
| 637 | + | RunnerName: rt.Cfg.Name, RunnerVersion: rt.Cfg.Version, RunnerEnvironment: rt.Cfg.environment(), | |
| 638 | 638 | }} | |
| 639 | 639 | _, exit, err := execstream.DriveJob(conn, run, j.cancelCh, execstream.JobHandler{ | |
| 640 | 640 | StepStarted: j.stepStarted, StepCompleted: j.stepCompleted, | |
| @@ -634,7 +634,7 @@ func (j *jobRun) drive(conn sandbox.Conn, rt *Runner) (*execpb.Exit, error) { | |||||
| 634 | WorkflowPath: j.job.WorkflowPath, WorkflowYaml: j.job.WorkflowYaml, JobKey: j.job.JobKey, | 634 | WorkflowPath: j.job.WorkflowPath, WorkflowYaml: j.job.WorkflowYaml, JobKey: j.job.JobKey, | ||
| 635 | Matrix: j.job.Matrix, Contexts: j.job.Contexts, Repo: j.job.Repo, TimeoutMinutes: int32(j.timeoutMinutes()), | 635 | Matrix: j.job.Matrix, Contexts: j.job.Contexts, Repo: j.job.Repo, TimeoutMinutes: int32(j.timeoutMinutes()), | ||
| 636 | DeadlineMs: max(1, time.Until(j.deadline()).Milliseconds()), | 636 | DeadlineMs: max(1, time.Until(j.deadline()).Milliseconds()), | ||
| 637 | - | RunnerName: rt.Cfg.Name, RunnerVersion: rt.Cfg.Version, RunnerEnvironment: "self-hosted", | 637 | + | RunnerName: rt.Cfg.Name, RunnerVersion: rt.Cfg.Version, RunnerEnvironment: rt.Cfg.environment(), |
| 638 | }} | 638 | }} | ||
| 639 | _, exit, err := execstream.DriveJob(conn, run, j.cancelCh, execstream.JobHandler{ | 639 | _, exit, err := execstream.DriveJob(conn, run, j.cancelCh, execstream.JobHandler{ | ||
| 640 | StepStarted: j.stepStarted, StepCompleted: j.stepCompleted, | 640 | StepStarted: j.stepStarted, StepCompleted: j.stepCompleted, | ||
M internal/host/runner_test.go +13 -1
| @@ -80,7 +80,7 @@ func TestTheJobTokenAndTheRunnerTokenStayApart(t *testing.T) { | |||
| 80 | 80 | h.run(t) | |
| 81 | 81 | eventually(t, "CompleteJob", func() bool { return h.srv.completeCount() == 1 }) | |
| 82 | 82 | // The sandbox gets the workflow and contexts, never a token. | |
| 83 | - | if sawJobSpec == nil || sawJobSpec.JobKey != "j" || sawJobSpec.RunnerName != "r1" || sawJobSpec.RunnerEnvironment != "self-hosted" || sawJobSpec.TimeoutMinutes != 5 { | |
| 83 | + | if sawJobSpec == nil || sawJobSpec.JobKey != "j" || sawJobSpec.RunnerName != "r1" || sawJobSpec.RunnerEnvironment != "github-hosted" || sawJobSpec.TimeoutMinutes != 5 { | |
| 84 | 84 | t.Fatalf("%v", sawJobSpec) | |
| 85 | 85 | } | |
| 86 | 86 | if strings.Contains(sawJobSpec.String(), "ermitejob_") || strings.Contains(sawJobSpec.String(), "ermiterun_") { | |
| @@ -785,6 +785,18 @@ func TestLoadConfig(t *testing.T) { | |||
| 785 | 785 | if c.URL != "https://ermite.example" || c.Name != "my-host.local" || strings.Join(c.Labels, ",") != "ubuntu-latest,Ubuntu-24.04" || c.Capacity != 2 { | |
| 786 | 786 | t.Fatalf("%+v", c) | |
| 787 | 787 | } | |
| 788 | + | if c.Environment != "github-hosted" { | |
| 789 | + | t.Errorf("default environment %q", c.Environment) | |
| 790 | + | } | |
| 791 | + | env[EnvEnvironment] = " Self-Hosted " | |
| 792 | + | if c, err := LoadConfig(func(k string) string { return env[k] }, "h", "/s", 1, ""); err != nil || c.Environment != "self-hosted" { | |
| 793 | + | t.Errorf("self-hosted: %q, %v", c.Environment, err) | |
| 794 | + | } | |
| 795 | + | env[EnvEnvironment] = "cloud" | |
| 796 | + | if _, err := LoadConfig(func(k string) string { return env[k] }, "h", "/s", 1, ""); err == nil || !strings.Contains(err.Error(), EnvEnvironment) { | |
| 797 | + | t.Errorf("an invalid environment was accepted: %v", err) | |
| 798 | + | } | |
| 799 | + | delete(env, EnvEnvironment) | |
| 788 | 800 | env[EnvName] = "bad name" | |
| 789 | 801 | if _, err := LoadConfig(func(k string) string { return env[k] }, "h", "/s", 1, ""); err == nil { | |
| 790 | 802 | t.Error("an invalid name was accepted") | |
| @@ -80,7 +80,7 @@ func TestTheJobTokenAndTheRunnerTokenStayApart(t *testing.T) { | |||||
| 80 | h.run(t) | 80 | h.run(t) | ||
| 81 | eventually(t, "CompleteJob", func() bool { return h.srv.completeCount() == 1 }) | 81 | eventually(t, "CompleteJob", func() bool { return h.srv.completeCount() == 1 }) | ||
| 82 | // The sandbox gets the workflow and contexts, never a token. | 82 | // The sandbox gets the workflow and contexts, never a token. | ||
| 83 | - | if sawJobSpec == nil || sawJobSpec.JobKey != "j" || sawJobSpec.RunnerName != "r1" || sawJobSpec.RunnerEnvironment != "self-hosted" || sawJobSpec.TimeoutMinutes != 5 { | 83 | + | if sawJobSpec == nil || sawJobSpec.JobKey != "j" || sawJobSpec.RunnerName != "r1" || sawJobSpec.RunnerEnvironment != "github-hosted" || sawJobSpec.TimeoutMinutes != 5 { |
| 84 | t.Fatalf("%v", sawJobSpec) | 84 | t.Fatalf("%v", sawJobSpec) | ||
| 85 | } | 85 | } | ||
| 86 | if strings.Contains(sawJobSpec.String(), "ermitejob_") || strings.Contains(sawJobSpec.String(), "ermiterun_") { | 86 | if strings.Contains(sawJobSpec.String(), "ermitejob_") || strings.Contains(sawJobSpec.String(), "ermiterun_") { | ||
| @@ -785,6 +785,18 @@ func TestLoadConfig(t *testing.T) { | |||||
| 785 | if c.URL != "https://ermite.example" || c.Name != "my-host.local" || strings.Join(c.Labels, ",") != "ubuntu-latest,Ubuntu-24.04" || c.Capacity != 2 { | 785 | if c.URL != "https://ermite.example" || c.Name != "my-host.local" || strings.Join(c.Labels, ",") != "ubuntu-latest,Ubuntu-24.04" || c.Capacity != 2 { | ||
| 786 | t.Fatalf("%+v", c) | 786 | t.Fatalf("%+v", c) | ||
| 787 | } | 787 | } | ||
| 788 | + | if c.Environment != "github-hosted" { | |||
| 789 | + | t.Errorf("default environment %q", c.Environment) | |||
| 790 | + | } | |||
| 791 | + | env[EnvEnvironment] = " Self-Hosted " | |||
| 792 | + | if c, err := LoadConfig(func(k string) string { return env[k] }, "h", "/s", 1, ""); err != nil || c.Environment != "self-hosted" { | |||
| 793 | + | t.Errorf("self-hosted: %q, %v", c.Environment, err) | |||
| 794 | + | } | |||
| 795 | + | env[EnvEnvironment] = "cloud" | |||
| 796 | + | if _, err := LoadConfig(func(k string) string { return env[k] }, "h", "/s", 1, ""); err == nil || !strings.Contains(err.Error(), EnvEnvironment) { | |||
| 797 | + | t.Errorf("an invalid environment was accepted: %v", err) | |||
| 798 | + | } | |||
| 799 | + | delete(env, EnvEnvironment) | |||
| 788 | env[EnvName] = "bad name" | 800 | env[EnvName] = "bad name" | ||
| 789 | if _, err := LoadConfig(func(k string) string { return env[k] }, "h", "/s", 1, ""); err == nil { | 801 | if _, err := LoadConfig(func(k string) string { return env[k] }, "h", "/s", 1, ""); err == nil { | ||
| 790 | t.Error("an invalid name was accepted") | 802 | t.Error("an invalid name was accepted") | ||