mirror of
https://github.com/luxfi/license.git
synced 2026-10-30 16:21:14 +00:00
- Stdlib-only deterministic binary token format (no JWT / CBOR dep). - Go API: VerifyToken, LoadFromEnv, HasFeature, HasFeatureOrDie. - Stable C ABI + C++17 RAII wrapper for non-Go commercial binaries (luxcpp/cevm). - cmd/lux-license: keygen / issue / inspect / verify. - Embedded development key; warns once at runtime until production key swap. - 22 Go tests + 1 cgo round-trip test, all passing.
98 lines
2.9 KiB
Go
98 lines
2.9 KiB
Go
// Copyright (C) 2020-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// Package captest builds the C archive of ../../, compiles test_capi.c
|
|
// against it, runs the resulting binary with $LUX_LICENSE set to a
|
|
// freshly-issued token, and asserts the C test exits 0.
|
|
//
|
|
// Lives in an internal sub-package because the cgo bridge itself must be
|
|
// `package main` (cgo c-archive build mode requirement) and `go test` cannot
|
|
// link against a synthesized main.
|
|
package captest_test
|
|
|
|
import (
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/luxfi/license"
|
|
)
|
|
|
|
func TestCAPIRoundTrip(t *testing.T) {
|
|
if _, err := exec.LookPath("cc"); err != nil {
|
|
t.Skipf("cc not in PATH: %v", err)
|
|
}
|
|
if testing.Short() {
|
|
t.Skip("skipping cgo build/link in short mode")
|
|
}
|
|
|
|
dir := t.TempDir()
|
|
|
|
// Locate the cgo bridge package (../../ relative to this test file).
|
|
// We resolve via the test's working directory; go test sets it to the
|
|
// package directory by default.
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatalf("getwd: %v", err)
|
|
}
|
|
bridgeDir := filepath.Clean(filepath.Join(wd, "..", ".."))
|
|
|
|
// 1. Build the C archive + header.
|
|
archive := filepath.Join(dir, "liblux_license.a")
|
|
build := exec.Command("go", "build", "-buildmode=c-archive", "-o", archive, ".")
|
|
build.Dir = bridgeDir
|
|
build.Env = append(os.Environ(), "GOWORK=off", "CGO_ENABLED=1")
|
|
if out, err := build.CombinedOutput(); err != nil {
|
|
t.Fatalf("c-archive build failed: %v\n%s", err, out)
|
|
}
|
|
|
|
// 2. Compile the C test against the archive.
|
|
bin := filepath.Join(dir, "test_capi")
|
|
cSrc := filepath.Join(bridgeDir, "testdata", "test_capi.c")
|
|
includeDir := filepath.Join(bridgeDir, "include")
|
|
cflags := []string{"-Wall", "-Wextra", "-Werror", "-O2", "-I" + includeDir, "-I" + bridgeDir, cSrc, archive, "-o", bin}
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
cflags = append(cflags, "-framework", "CoreFoundation", "-framework", "Security")
|
|
case "linux":
|
|
cflags = append(cflags, "-lpthread", "-ldl", "-lm")
|
|
default:
|
|
t.Skipf("unsupported OS for capi test: %s", runtime.GOOS)
|
|
}
|
|
link := exec.Command("cc", cflags...)
|
|
if out, err := link.CombinedOutput(); err != nil {
|
|
t.Fatalf("cc link failed: %v\n%s", err, out)
|
|
}
|
|
|
|
// 3. Issue a token signed by the dev key.
|
|
priv := license.DevPrivateKey()
|
|
c := &license.Claims{
|
|
CustomerID: "Acme Inc",
|
|
LicenseID: "lic_capi_test_0001",
|
|
IssuedAt: time.Now().UTC().Truncate(time.Second),
|
|
Expiry: time.Now().UTC().Add(24 * time.Hour),
|
|
Scope: []string{"gpu", "dex", "fpga"},
|
|
}
|
|
tok, err := license.Sign(c, priv)
|
|
if err != nil {
|
|
t.Fatalf("sign: %v", err)
|
|
}
|
|
b64 := license.EncodeBase64(tok)
|
|
|
|
// 4. Run the C test binary.
|
|
run := exec.Command(bin)
|
|
run.Env = append(os.Environ(),
|
|
"LUX_LICENSE="+b64,
|
|
"LUX_LICENSE_FILE=",
|
|
"LUX_LICENSE_SUPPRESS_DEV_WARNING=1",
|
|
)
|
|
out, err := run.CombinedOutput()
|
|
t.Logf("test_capi output:\n%s", out)
|
|
if err != nil {
|
|
t.Fatalf("test_capi failed: %v", err)
|
|
}
|
|
}
|