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
13 changes: 9 additions & 4 deletions .github/workflows/validate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ jobs:
go:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache: false
Expand All @@ -24,7 +24,12 @@ jobs:
secret-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v2
- uses: actions/setup-go@v7
with:
go-version-file: go.mod
cache: false
- name: Scan Git history with Gitleaks
run: go run github.com/zricethezav/gitleaks/v8@v8.30.1 git --no-banner --redact .
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Go-first validation and sanitized evidence for the
[Edge-Computing-LLM](https://github.com/Edge-Computing-LLM) project family.
The harness checks repository quality, Helm profiles, the local Ubuntu + k3s +
NVIDIA GPU substrate, the deployed observability stack, and the fixed Qwen
NVIDIA GPU substrate, the deployed observability stack, and a selectable GGUF
runtime smoke contract from one reproducible command.

The project is an evidence plane, not a deployment layer. It does not install,
Expand All @@ -18,7 +18,7 @@ through the owning repository.
| `edge-cli` | module integrity, formatting, unit/race tests, vet, vulnerability scan, build, read-only infrastructure validation |
| `k3s-nvidia-edge` | module integrity, formatting, unit/race tests, vet, vulnerability scan, build, Helm lint/render, read-only doctor |
| `llm-observability-stack` | module integrity, formatting, unit/race tests, vet, vulnerability scan, three Go builds, Helm dependencies/lint, five render profiles, live doctor |
| `qwen-gguf-observability` | module integrity, formatting, unit/race tests, vet, vulnerability scan, build, live contract validation, fixed smoke probe |
| `gguf-observability` | module integrity, formatting, unit/race tests, vet, vulnerability scan, build, model-selectable live contract validation, fixed smoke probe |
| Local platform | Ubuntu/kernel/tool versions, NVIDIA GPU, node readiness, RuntimeClass, GPU resource, workloads, releases, and storage |
| Dashboard candidates | existing Git integrity plus available lint/test/build scripts; dependencies are never installed or changed |

Expand All @@ -34,6 +34,18 @@ and `nvidia-smi`. From this repository:
go run ./cmd/edge-llm-tests -mode all -root ..
```

Select the currently deployed model through the observer's environment contract,
for example:

```bash
GGUF_MODEL=llama3-2-1b-local \
GGUF_VRAM_CEILING_MIB=900 \
GGUF_EXPECTED_NUM_GPU=8 \
GGUF_EXPECTED_NUM_CTX=256 \
GGUF_EXPECTED_NUM_BATCH=1 \
go run ./cmd/edge-llm-tests -mode cluster -root ..
```

Useful focused runs:

```bash
Expand All @@ -54,11 +66,11 @@ Each run creates a UTC-stamped directory under `results/`:
results/20260719T120000Z/
├── report.md human-readable outcome and bounded failure details
├── summary.json versioned machine-readable evidence
└── qwen-smoke.json privacy-safe smoke metadata, when the probe runs
└── gguf-smoke.json privacy-safe smoke metadata, when the probe runs
```

Result files are intentionally suitable for source control. Commands and
bounded output pass through the sanitizer. The Qwen artifact records only the
bounded output pass through the sanitizer. The GGUF artifact records only the
model identifier, observation time, duration, and pass state; the prompt and
model response are never stored. See [the evidence policy](docs/EVIDENCE-POLICY.md).

Expand Down
8 changes: 8 additions & 0 deletions internal/sanitize/sanitize.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package sanitize

import (
"os"
"os/user"
"regexp"
"strings"
)
Expand All @@ -22,6 +24,12 @@ func Text(value string) string {
value = ipv4.ReplaceAllString(value, "[redacted-ip]")
value = homePath.ReplaceAllString(value, "/home/[redacted-user]")
value = mediaPath.ReplaceAllString(value, "/media/[redacted-user]")
if current, err := user.Current(); err == nil && current.Username != "" {
value = strings.ReplaceAll(value, current.Username, "[redacted-user]")
}
if hostname, err := os.Hostname(); err == nil && hostname != "" {
value = strings.ReplaceAll(value, hostname, "[redacted-host]")
}
return strings.TrimSpace(value)
}

Expand Down
11 changes: 11 additions & 0 deletions internal/sanitize/sanitize_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sanitize

import (
"os"
"strings"
"testing"
)
Expand All @@ -14,3 +15,13 @@ func TestTextRedactsSensitiveEvidence(t *testing.T) {
}
}
}

func TestTextRedactsLocalIdentity(t *testing.T) {
hostname, err := os.Hostname()
if err != nil || hostname == "" {
t.Skip("hostname unavailable")
}
if got := Text("node=" + hostname); strings.Contains(got, hostname) {
t.Fatalf("hostname was not redacted: %s", got)
}
}
6 changes: 3 additions & 3 deletions internal/suite/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ func ClusterChecks(ctx context.Context, root, resultsDir string, run runner.Runn
{ID: "cluster:helm-releases", Scope: "cluster", Description: "Inspect deployed Helm releases", Name: "helm", Args: []string{"list", "-A"}, Required: true, Timeout: time.Minute},
{ID: "cluster:storage", Scope: "cluster", Description: "Inspect storage classes and claims", Name: "kubectl", Args: []string{"get", "storageclass,pvc", "-A"}, Required: true, Timeout: time.Minute},
{ID: "edge-cli:validate-infra", Scope: "live-validation", Description: "Run unified read-only infrastructure validation", Dir: root + "/edge-cli", Name: "go", Args: []string{"run", "./cmd/edge", "--timeout", "2m", "validate", "infra", "--skip-cuda"}, Required: true, Timeout: 5 * time.Minute},
{ID: "k3s-nvidia-edge:doctor", Scope: "live-validation", Description: "Run Layer 1 read-only host and cluster diagnostics", Dir: root + "/k3s-nvidia-edge", Name: "go", Args: []string{"run", "./cmd/k3s-nvidia-edge", "doctor", "--sudo=false"}, Required: true, Timeout: 5 * time.Minute},
{ID: "k3s-nvidia-edge:doctor", Scope: "live-validation", Description: "Run Layer 1 read-only host and cluster diagnostics", Dir: root + "/k3s-nvidia-edge", Name: "go", Args: []string{"run", "./cmd/k3s-nvidia-edge", "doctor", "--sudo=false"}, Required: true, OmitOutput: true, Timeout: 5 * time.Minute},
{ID: "llm-observability-stack:doctor", Scope: "live-validation", Description: "Run Layer 2 read-only diagnostics", Dir: root + "/llm-observability-stack", Name: "go", Args: []string{"run", "./cmd/llm-observability", "doctor", "-timeout", "1m"}, Required: true, Timeout: 3 * time.Minute},
{ID: "qwen-gguf-observability:validate", Scope: "live-validation", Description: "Validate local Qwen observability state", Dir: root + "/qwen-gguf-observability", Name: "go", Args: []string{"run", "./cmd/qwen-observe", "validate"}, Required: true, Timeout: 3 * time.Minute},
{ID: "qwen-gguf-observability:smoke", Scope: "live-validation", Description: "Run the fixed, privacy-safe Qwen smoke probe", Dir: root + "/qwen-gguf-observability", Name: "go", Args: []string{"run", "./cmd/qwen-observe", "smoke", "--output", resultsDir + "/qwen-smoke.json"}, Required: true, OmitOutput: true, Timeout: 5 * time.Minute},
{ID: "gguf-observability:validate", Scope: "live-validation", Description: "Validate the selected local GGUF model contract", Dir: root + "/gguf-observability", Name: "go", Args: []string{"run", "./cmd/gguf-observe", "validate"}, Required: true, Timeout: 3 * time.Minute},
{ID: "gguf-observability:smoke", Scope: "live-validation", Description: "Run the fixed, privacy-safe GGUF model smoke probe", Dir: root + "/gguf-observability", Name: "go", Args: []string{"run", "./cmd/gguf-observe", "smoke", "--output", resultsDir + "/gguf-smoke.json"}, Required: true, OmitOutput: true, Timeout: 5 * time.Minute},
}
checks := make([]model.Check, 0, len(specs)+1)
for _, spec := range specs {
Expand Down
8 changes: 5 additions & 3 deletions internal/suite/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
"github.com/Edge-Computing-LLM/edge-llm-tests/internal/runner"
)

var organizationRepos = []string{"edge-cli", "k3s-nvidia-edge", "llm-observability-stack", "qwen-gguf-observability"}
var organizationRepos = []string{"edge-cli", "k3s-nvidia-edge", "llm-observability-stack", "gguf-observability"}

func RepositoryChecks(ctx context.Context, root string, run runner.Runner, includeCandidates bool) ([]model.Repository, []model.Check) {
buildDir, err := os.MkdirTemp("", "edge-llm-tests-builds-")
Expand Down Expand Up @@ -139,14 +139,16 @@ func repositoryPlan(name, path, buildDir string, run runner.Runner, ctx context.
{"cpu", []string{"-f", "values.cpu-k3s.yaml"}},
{"local", []string{"-f", "values.local-k3s.example.yaml"}},
{"geforce", []string{"-f", "values.geforce-940m-k3s.yaml"}},
{"geforce-gemma", []string{"-f", "values.geforce-940m-k3s.yaml", "-f", "values.gemma-3-1b-geforce-940m-k3s.yaml"}},
{"geforce-llama", []string{"-f", "values.geforce-940m-k3s.yaml", "-f", "values.llama3.2-1b-geforce-940m-k3s.yaml"}},
{"full-nvidia", []string{"-f", "values.full-stack-nvidia.example.yaml", "--set", "langsmith.existingSecret=", "--set", "openWebUI.existingSecret=", "--set", "open-webui.webuiSecret.existingSecretName="}},
}
for _, profile := range profiles {
args := append([]string{"template", "llm-observability-stack", "."}, profile.args...)
specs = append(specs, runner.Spec{ID: name + ":helm-render-" + profile.id, Scope: name, Description: "Render " + profile.id + " Helm profile", Dir: path, Name: "helm", Args: args, Required: true, OmitOutput: true})
}
case "qwen-gguf-observability":
specs = append(specs, runner.Spec{ID: name + ":build", Scope: name, Description: "Build read-only Qwen observer", Dir: path, Name: "go", Args: []string{"build", "-o", filepath.Join(buildDir, "qwen-observe"), "./cmd/qwen-observe"}, Required: true})
case "gguf-observability":
specs = append(specs, runner.Spec{ID: name + ":build", Scope: name, Description: "Build read-only GGUF observer", Dir: path, Name: "go", Args: []string{"build", "-o", filepath.Join(buildDir, "gguf-observe"), "./cmd/gguf-observe"}, Required: true})
}
checks := make([]model.Check, 0, len(specs))
for _, spec := range specs {
Expand Down
6 changes: 6 additions & 0 deletions results/20260719T043235Z/qwen-smoke.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"observed_at": "2026-07-19T04:33:47Z",
"model": "qwen-1-8b-chat-q4-k-m-local",
"duration_seconds": 1.332,
"passed": true
}
Loading