Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,8 @@ jobs:
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Install bats
run: sudo apt-get install -y bats
- run: go vet ./...
- run: CGO_ENABLED=0 go test ./...
- name: Build binary for bats
run: CGO_ENABLED=0 go build -o harness .
- run: bats test/preflight.bats

lint:
runs-on: ubuntu-latest
Expand Down
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## OpenShell Harness — build, push, and test
##
## Tests (CI mode auto-detects from CI env var):
## make test # vet + unit + bats (~2min)
## make test # vet + unit tests
## make test-local # local gateway integration
## make test-kind # kind integration (self-contained cluster)
## make test-remote # OCP integration (needs KUBECONFIG)
Expand Down Expand Up @@ -54,10 +54,9 @@ lint:
## CI mode auto-detects from the CI env var (set by GitHub Actions).
## Locally: full tests with credentials. On GHA: no-credential mode.

## Vet + unit tests + bats (fast, ~2min, no gateway needed)
## Vet + unit tests
test: vet
CGO_ENABLED=0 go test ./...
bats test/preflight.bats

## Local gateway integration (unit tests run separately via 'make test')
test-local: cli
Expand Down
2 changes: 1 addition & 1 deletion agents/demo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# harness up --local --agent demo

name: demo
entrypoint: claude -p
entrypoint: claude
task: demo/DEMO-TASK.md
tty: false

Expand Down
22 changes: 22 additions & 0 deletions agents/opencode.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# OpenCode agent configuration.
#
# Usage:
# harness up -f agents/opencode.yaml
# harness up --agent opencode

name: opencode-agent
entrypoint: opencode
tty: true

providers:
- profile: github
- profile: vertex-local
- profile: atlassian
config:
JIRA_URL: ${JIRA_URL}
JIRA_USERNAME: ${JIRA_USERNAME}
- profile: gws

env:
ANTHROPIC_BASE_URL: https://inference.local
ANTHROPIC_API_KEY: sk-ant-openshell-proxy-managed
46 changes: 8 additions & 38 deletions cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@ package cmd
import (
"fmt"
"os"
"path/filepath"
"slices"
"time"

"github.com/robbycochran/harness-openshell/internal/agent"
"github.com/robbycochran/harness-openshell/internal/gateway"
"github.com/robbycochran/harness-openshell/internal/preflight"
"github.com/robbycochran/harness-openshell/internal/status"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -56,51 +53,24 @@ func NewCreateCmd(harnessDir, cli string) *cobra.Command {
status.Infof("Name: %s", name)
status.Infof("Image: %s", sandboxImage)

// 3. Validate providers are registered
// 3. Ensure providers are registered
status.Header("Providers")
providerNames := agentCfg.ProviderNames()
registered, missing := gateway.ValidateProviders(providerNames, gw)
if len(missing) > 0 {
if err := registerProviders(harnessDir, gw, false, nil, false); err != nil {
status.Warn(fmt.Sprintf("provider registration: %v", err))
}
registered, missing = gateway.ValidateProviders(providerNames, gw)
}
for _, n := range registered {
status.OKf("%s: attached", n)
}
for _, n := range missing {
status.Failf("%s: not registered", n)
}
if len(missing) > 0 && len(registered) == 0 {
return fmt.Errorf("no providers available — run: harness providers")
}

// 4. Load provider definitions
providersPath := filepath.Join(harnessDir, "providers.toml")
allProviders, _ := preflight.LoadProviders(providersPath)

// 5. Run preflight checks (only for unregistered providers)
if len(missing) > 0 && allProviders != nil {
status.Header("Preflight")
preflightOK := true
for _, p := range allProviders {
if !slices.Contains(missing, p.Name) {
continue
}
ok, details := preflight.CheckProvider(p)
if ok {
status.OKf("%s: ready", p.Name)
} else {
status.Failf("%s: prerequisites missing", p.Name)
if p.Required {
preflightOK = false
}
}
for _, d := range details {
status.Detail(d)
}
}
if !preflightOK {
return fmt.Errorf("preflight checks failed — fix issues above")
}
}

// 6. Deploy the sandbox
// 4. Deploy the sandbox
status.Header("Creating sandbox")
payloadDir, err := os.MkdirTemp("", "harness-payload-")
if err != nil {
Expand Down
9 changes: 1 addition & 8 deletions cmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/robbycochran/harness-openshell/internal/gateway"
"github.com/robbycochran/harness-openshell/internal/k8s"
"github.com/robbycochran/harness-openshell/internal/preflight"
"github.com/robbycochran/harness-openshell/internal/status"
"github.com/spf13/cobra"
)
Expand All @@ -26,7 +25,7 @@ func NewDeployCmd(harnessDir, cli string) *cobra.Command {
cmd := &cobra.Command{
Use: "deploy [gateway]",
Short: "Deploy or verify the gateway",
Long: "Deploy a gateway by name (e.g., local, ocp, kind). Reads configuration from gateways/<name>/gateway.toml.",
Long: "Deploy a gateway by name (e.g., local, ocp, kind). Reads configuration from gateways/<name>/gateway.yaml.",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
gatewayName, err := resolveGatewayName(args, local, remote)
Expand Down Expand Up @@ -148,12 +147,6 @@ func deployFromConfig(harnessDir string, gwCfg *gateway.GatewayConfig, gw gatewa
namespace := k8s.DefaultNamespace()

chartVersion := os.Getenv("OPENSHELL_CHART_VERSION")
if chartVersion == "" {
cfg, _ := preflight.LoadConfig(filepath.Join(harnessDir, "openshell.toml"))
if cfg != nil && cfg.Upstream.ChartVersion != "" {
chartVersion = cfg.Upstream.ChartVersion
}
}
if chartVersion == "" {
chartVersion = gwCfg.Chart.Version
}
Expand Down
73 changes: 33 additions & 40 deletions cmd/deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,27 @@ func setupOCPGatewayConfig(t *testing.T, dir string) string {
gwDir := filepath.Join(dir, "gateways", "ocp")
os.MkdirAll(filepath.Join(gwDir, "helm"), 0o755)
os.MkdirAll(filepath.Join(gwDir, "addons"), 0o755)
os.WriteFile(filepath.Join(gwDir, "gateway.toml"), []byte(`
[gateway]
type = "remote"
platform = "ocp"
service = "route"
name = "test-ocp"

[chart]
oci = "oci://ghcr.io/nvidia/openshell/helm-chart"
version = "0.0.58"
[chart.crd]
url = "https://example.com/crd.yaml"

[helm]
values = "values.yaml"

[addons]
manifests = ["addons/rbac.yaml", "addons/route.yaml"]

[ocp]
scc-privileged = ["sa1", "sa2"]
scc-anyuid = ["sa1"]

[secrets]
names = ["secret-a"]
mtls = "test-client-tls"
os.WriteFile(filepath.Join(gwDir, "gateway.yaml"), []byte(`
gateway:
type: remote
platform: ocp
service: route
name: test-ocp
chart:
oci: oci://ghcr.io/nvidia/openshell/helm-chart
version: "0.0.58"
crd:
url: https://example.com/crd.yaml
helm:
values: values.yaml
addons:
manifests: [addons/rbac.yaml, addons/route.yaml]
ocp:
scc-privileged: [sa1, sa2]
scc-anyuid: [sa1]
secrets:
names: [secret-a]
mtls: test-client-tls
`), 0o644)
os.WriteFile(filepath.Join(gwDir, "helm", "values.yaml"), []byte("image:\n pullPolicy: Always\n"), 0o644)
os.WriteFile(filepath.Join(gwDir, "addons", "rbac.yaml"), []byte("# rbac\n"), 0o644)
Expand All @@ -60,20 +55,18 @@ func setupK8sGatewayConfig(t *testing.T, dir string) string {
t.Helper()
gwDir := filepath.Join(dir, "gateways", "kind")
os.MkdirAll(gwDir, 0o755)
os.WriteFile(filepath.Join(gwDir, "gateway.toml"), []byte(`
[gateway]
type = "remote"
platform = "k8s"
service = "nodeport"
name = "test-kind"
mode = "direct"

[chart]
oci = "oci://ghcr.io/nvidia/openshell/helm-chart"
version = "0.0.58"
[chart.crd]
url = "https://example.com/crd.yaml"

os.WriteFile(filepath.Join(gwDir, "gateway.yaml"), []byte(`
gateway:
type: remote
platform: k8s
service: nodeport
name: test-kind
mode: direct
chart:
oci: oci://ghcr.io/nvidia/openshell/helm-chart
version: "0.0.58"
crd:
url: https://example.com/crd.yaml
`), 0o644)
return gwDir
}
Expand Down
36 changes: 0 additions & 36 deletions cmd/preflight.go

This file was deleted.

18 changes: 0 additions & 18 deletions cmd/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,9 @@ import (

"github.com/robbycochran/harness-openshell/internal/gateway"
"github.com/robbycochran/harness-openshell/internal/status"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)

func NewProvidersCmd(harnessDir, cli string) *cobra.Command {
var force bool

cmd := &cobra.Command{
Use: "providers",
Short: "Register providers with the gateway",
RunE: func(cmd *cobra.Command, args []string) error {
gw := gateway.New(cli)
return registerProviders(harnessDir, gw, force, nil, true)
},
}

cmd.Flags().BoolVar(&force, "force", false, "Delete and recreate all providers")

return cmd
}

// registerProviders registers providers with the gateway. If gwCfg is non-nil
// and has a [providers] section, only providers in that list are registered.
// Otherwise all providers are registered (backward-compatible behavior).
Expand Down
Loading
Loading