rebrand: Switchboard Core → Armature
- Rename Go module switchboard-core → armature (155+ files) - Rename Docker image → gobha/armature - Rename K8s resources, secrets, deployments - Rename Prometheus metrics switchboard_* → armature_* - Rename env vars SWITCHBOARD_ADMIN_* → ARMATURE_ADMIN_* - Rename DB names switchboard_core* → armature* - Update all frontend branding, notification templates, docs - Update CI scripts, e2e tests, Keycloak realm, nginx conf - Rename scripts/switchboard-ca.sh → scripts/armature-ca.sh - Rename k8s/switchboard.yaml → k8s/armature.yaml - Rename chart alerting/dashboard files - Fix: DockerHub push uses env: binding for secret injection - Helm chart updated (name, labels, template functions, dashboard, alerting) - Replace favicon/icon assets with Armature brand No functional changes. Pure mechanical rename + CI fix. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Switchboard Core - Server Environment Variables
|
||||
# Armature - Server Environment Variables
|
||||
# Copy this file to .env and fill in the values
|
||||
|
||||
# ── Server ───────────────────────────────────
|
||||
@@ -9,9 +9,9 @@ BASE_PATH= # e.g. /chat for path-based routing
|
||||
# ── Database (PostgreSQL) ────────────────────
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_USER=switchboard_core
|
||||
DB_USER=armature
|
||||
DB_PASSWORD=your-secure-password-here
|
||||
DB_NAME=switchboard_core
|
||||
DB_NAME=armature
|
||||
DB_SSL_MODE=disable
|
||||
DB_MAX_CONNS=25
|
||||
|
||||
@@ -20,19 +20,19 @@ JWT_SECRET=your-super-secret-jwt-key-change-in-production
|
||||
# JWT durations (hardcoded in handlers/auth.go — not configurable via env):
|
||||
# Access token: 15 minutes
|
||||
# Refresh token: 7 days
|
||||
JWT_ISSUER=switchboard-core
|
||||
JWT_ISSUER=armature
|
||||
|
||||
# ── Bootstrap Admin ──────────────────────────
|
||||
# Creates or updates admin account on every startup.
|
||||
# Set via K8s secret or env. Leave blank to skip.
|
||||
SWITCHBOARD_ADMIN_USERNAME=
|
||||
SWITCHBOARD_ADMIN_PASSWORD=
|
||||
ARMATURE_ADMIN_USERNAME=
|
||||
ARMATURE_ADMIN_PASSWORD=
|
||||
|
||||
# ── Seed Users (dev/test only) ──────────────
|
||||
# Pre-create users on startup. Ignored in production.
|
||||
# Format: user:pass:role,user2:pass2:role2 (role = admin|user, default: user)
|
||||
# Idempotent: existing usernames are skipped.
|
||||
# K8s: create secret "switchboard-seed-users" with key "users"
|
||||
# K8s: create secret "armature-seed-users" with key "users"
|
||||
SEED_USERS=
|
||||
|
||||
# ── CORS ─────────────────────────────────────
|
||||
@@ -57,7 +57,7 @@ STORAGE_PATH=/data/storage
|
||||
# S3 settings (only when STORAGE_BACKEND=s3)
|
||||
# Works with MinIO, Ceph RGW, AWS S3.
|
||||
# S3_ENDPOINT=http://minio:9000
|
||||
# S3_BUCKET=switchboard-storage
|
||||
# S3_BUCKET=armature-storage
|
||||
# S3_ACCESS_KEY=
|
||||
# S3_SECRET_KEY=
|
||||
# S3_REGION=us-east-1
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
type Mode string
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
const bcryptCost = 12
|
||||
|
||||
@@ -109,7 +109,7 @@ func (m *mockIdP) issueToken(sub, email, name string, groups []string, roles []s
|
||||
claims := jwt.MapClaims{
|
||||
"iss": m.server.URL,
|
||||
"sub": sub,
|
||||
"aud": "switchboard",
|
||||
"aud": "armature",
|
||||
"exp": time.Now().Add(1 * time.Hour).Unix(),
|
||||
"iat": time.Now().Unix(),
|
||||
"email": email,
|
||||
@@ -140,7 +140,7 @@ func (m *mockIdP) issueExpiredToken(sub string) string {
|
||||
claims := jwt.MapClaims{
|
||||
"iss": m.server.URL,
|
||||
"sub": sub,
|
||||
"aud": "switchboard",
|
||||
"aud": "armature",
|
||||
"exp": time.Now().Add(-1 * time.Hour).Unix(),
|
||||
"iat": time.Now().Add(-2 * time.Hour).Unix(),
|
||||
}
|
||||
@@ -160,7 +160,7 @@ func (m *mockIdP) issueTokenBadIssuer(sub string) string {
|
||||
claims := jwt.MapClaims{
|
||||
"iss": "https://evil.example.com",
|
||||
"sub": sub,
|
||||
"aud": "switchboard",
|
||||
"aud": "armature",
|
||||
"exp": time.Now().Add(1 * time.Hour).Unix(),
|
||||
"iat": time.Now().Unix(),
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ParseDN parses an RFC 2253 / RFC 4514 distinguished name into key-value pairs.
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ErrNoCert is returned when no client certificate is presented on a
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ── Test CA helpers ──────────────────────────────────────────────────
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// MTLSProxyConfig holds configuration for the proxy-terminated mTLS provider.
|
||||
|
||||
@@ -3,7 +3,7 @@ package auth
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
func TestParseDN(t *testing.T) {
|
||||
|
||||
@@ -18,17 +18,17 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// OIDCConfig holds OIDC-specific configuration from env vars.
|
||||
type OIDCConfig struct {
|
||||
IssuerURL string // e.g. "https://keycloak.corp/realms/switchboard"
|
||||
IssuerURL string // e.g. "https://keycloak.corp/realms/armature"
|
||||
ExternalIssuerURL string // browser-facing URL (optional, defaults to IssuerURL)
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
RedirectURL string // e.g. "https://switchboard.corp/api/v1/auth/oidc/callback"
|
||||
RedirectURL string // e.g. "https://armature.corp/api/v1/auth/oidc/callback"
|
||||
AutoActivate bool // auto-activate new users (default true)
|
||||
DefaultTeam string // team ID for auto-provisioned users (optional)
|
||||
RolesClaim string // JWT claim for role mapping (default "realm_access.roles")
|
||||
@@ -435,7 +435,7 @@ func (p *OIDCProvider) extractGroups(claims *oidcClaims) []string {
|
||||
// Keycloak puts groups in different places depending on mapper config.
|
||||
// Try the configured claim path as a fallback.
|
||||
// The claims.Groups field handles the simple case. This handles
|
||||
// nested paths like "resource_access.switchboard.roles".
|
||||
// nested paths like "resource_access.armature.roles".
|
||||
// For now, return empty — the direct Groups field covers the
|
||||
// standard Keycloak group mapper output.
|
||||
return nil
|
||||
|
||||
@@ -3,7 +3,7 @@ package auth_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"switchboard-core/auth"
|
||||
"armature/auth"
|
||||
)
|
||||
|
||||
func TestOIDCProvider_Discovery(t *testing.T) {
|
||||
@@ -12,7 +12,7 @@ func TestOIDCProvider_Discovery(t *testing.T) {
|
||||
|
||||
p, err := auth.NewOIDCProvider(auth.OIDCConfig{
|
||||
IssuerURL: idp.IssuerURL(),
|
||||
ClientID: "switchboard",
|
||||
ClientID: "armature",
|
||||
ClientSecret: "secret",
|
||||
AutoActivate: true,
|
||||
})
|
||||
@@ -38,7 +38,7 @@ func TestOIDCProvider_Mode(t *testing.T) {
|
||||
|
||||
p, err := auth.NewOIDCProvider(auth.OIDCConfig{
|
||||
IssuerURL: idp.IssuerURL(),
|
||||
ClientID: "switchboard",
|
||||
ClientID: "armature",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("NewOIDCProvider: %v", err)
|
||||
@@ -55,7 +55,7 @@ func TestOIDCProvider_NoRegistration(t *testing.T) {
|
||||
|
||||
p, err := auth.NewOIDCProvider(auth.OIDCConfig{
|
||||
IssuerURL: idp.IssuerURL(),
|
||||
ClientID: "switchboard",
|
||||
ClientID: "armature",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("NewOIDCProvider: %v", err)
|
||||
@@ -68,7 +68,7 @@ func TestOIDCProvider_NoRegistration(t *testing.T) {
|
||||
|
||||
func TestOIDCProvider_MissingIssuer(t *testing.T) {
|
||||
_, err := auth.NewOIDCProvider(auth.OIDCConfig{
|
||||
ClientID: "switchboard",
|
||||
ClientID: "armature",
|
||||
})
|
||||
if err == nil {
|
||||
t.Error("expected error for missing issuer URL")
|
||||
@@ -93,7 +93,7 @@ func TestOIDCProvider_AuthorizationURL(t *testing.T) {
|
||||
|
||||
p, err := auth.NewOIDCProvider(auth.OIDCConfig{
|
||||
IssuerURL: idp.IssuerURL(),
|
||||
ClientID: "switchboard",
|
||||
ClientID: "armature",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("NewOIDCProvider: %v", err)
|
||||
@@ -105,7 +105,7 @@ func TestOIDCProvider_AuthorizationURL(t *testing.T) {
|
||||
}
|
||||
|
||||
// Should contain the required OIDC parameters
|
||||
for _, want := range []string{"response_type=code", "client_id=switchboard", "state=test-state", "nonce=test-nonce"} {
|
||||
for _, want := range []string{"response_type=code", "client_id=armature", "state=test-state", "nonce=test-nonce"} {
|
||||
if !containsStr(url, want) {
|
||||
t.Errorf("AuthorizationURL missing %q in %q", want, url)
|
||||
}
|
||||
@@ -115,7 +115,7 @@ func TestOIDCProvider_AuthorizationURL(t *testing.T) {
|
||||
func TestOIDCProvider_UnreachableIssuer(t *testing.T) {
|
||||
_, err := auth.NewOIDCProvider(auth.OIDCConfig{
|
||||
IssuerURL: "http://127.0.0.1:1/unreachable",
|
||||
ClientID: "switchboard",
|
||||
ClientID: "armature",
|
||||
})
|
||||
if err == nil {
|
||||
t.Error("expected error for unreachable issuer")
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/store"
|
||||
"armature/database"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// EveryoneGroupID is the stable ID of the implicit "Everyone" group seeded in
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ConnCounter provides WebSocket connection count (satisfied by events.Hub).
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// mockClusterStore implements store.ClusterStore for unit tests.
|
||||
|
||||
@@ -44,7 +44,7 @@ type Config struct {
|
||||
S3Region string // AWS region (default "us-east-1")
|
||||
S3AccessKey string // access key ID
|
||||
S3SecretKey string // secret access key
|
||||
S3Prefix string // optional key prefix within bucket (e.g. "switchboard/")
|
||||
S3Prefix string // optional key prefix within bucket (e.g. "armature/")
|
||||
S3ForcePathStyle bool // use path-style URLs (required for MinIO, most self-hosted)
|
||||
|
||||
// Structured logging
|
||||
@@ -85,11 +85,11 @@ type Config struct {
|
||||
BundledPackages string
|
||||
|
||||
// OIDC
|
||||
OIDCIssuerURL string // e.g. "https://keycloak.corp/realms/switchboard"
|
||||
OIDCIssuerURL string // e.g. "https://keycloak.corp/realms/armature"
|
||||
OIDCExternalIssuerURL string // OIDC_EXTERNAL_ISSUER_URL
|
||||
OIDCClientID string
|
||||
OIDCClientSecret string
|
||||
OIDCRedirectURL string // e.g. "https://switchboard.corp/api/v1/auth/oidc/callback"
|
||||
OIDCRedirectURL string // e.g. "https://armature.corp/api/v1/auth/oidc/callback"
|
||||
OIDCAutoActivate bool // auto-activate new users (default true)
|
||||
OIDCDefaultTeam string // team ID for auto-provisioned users (optional)
|
||||
OIDCRolesClaim string // JWT claim for role mapping (default "realm_access.roles")
|
||||
@@ -127,9 +127,9 @@ func Load() *Config {
|
||||
JWTSecret: getEnv("JWT_SECRET", "dev-secret-change-me"),
|
||||
Environment: getEnv("ENVIRONMENT", "development"),
|
||||
BasePath: sanitizeBasePath(getEnv("BASE_PATH", "")),
|
||||
AdminUsername: getEnv("SWITCHBOARD_ADMIN_USERNAME", ""),
|
||||
AdminPassword: getEnv("SWITCHBOARD_ADMIN_PASSWORD", ""),
|
||||
AdminEmail: getEnv("SWITCHBOARD_ADMIN_EMAIL", ""),
|
||||
AdminUsername: getEnv("ARMATURE_ADMIN_USERNAME", ""),
|
||||
AdminPassword: getEnv("ARMATURE_ADMIN_PASSWORD", ""),
|
||||
AdminEmail: getEnv("ARMATURE_ADMIN_EMAIL", ""),
|
||||
SeedUsers: getEnv("SEED_USERS", ""),
|
||||
EncryptionKey: getEnv("ENCRYPTION_KEY", ""),
|
||||
|
||||
@@ -207,7 +207,7 @@ func resolveDatabaseURL() string {
|
||||
port := getEnv("POSTGRES_PORT", "5432")
|
||||
user := getEnv("POSTGRES_USER", "")
|
||||
pass := getEnv("POSTGRES_PASSWORD", "")
|
||||
db := getEnv("POSTGRES_DB", "switchboard_core")
|
||||
db := getEnv("POSTGRES_DB", "armature")
|
||||
ssl := getEnv("POSTGRES_SSLMODE", "disable")
|
||||
return fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s", user, pass, host, port, db, ssl)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// switchboard vault rekey
|
||||
// armature vault rekey
|
||||
// ENCRYPTION_KEY = current/old key
|
||||
// NEW_ENCRYPTION_KEY = new key to re-encrypt with
|
||||
func Rekey(db *sql.DB, oldEnvKey, newEnvKey string) error {
|
||||
|
||||
@@ -13,7 +13,7 @@ type VaultStatusInfo struct {
|
||||
}
|
||||
|
||||
// VaultStatus gathers vault health metrics from the database.
|
||||
// Used by both the CLI (`switchboard vault status`) and the admin API endpoint.
|
||||
// Used by both the CLI (`armature vault status`) and the admin API endpoint.
|
||||
func VaultStatus(db *sql.DB, encryptionKey string) (*VaultStatusInfo, error) {
|
||||
if db == nil {
|
||||
return nil, fmt.Errorf("database not available")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Package crypto provides API key encryption primitives for Switchboard Core.
|
||||
// Package crypto provides API key encryption primitives for Armature.
|
||||
//
|
||||
// Two-tier model:
|
||||
//
|
||||
@@ -59,7 +59,7 @@ func DeriveKeyFromEnv(envValue string) ([]byte, error) {
|
||||
}
|
||||
// HKDF with SHA-256: extract + expand with context string for domain separation.
|
||||
// No salt (nil) — the env value itself is the input keying material.
|
||||
hkdfReader := hkdf.New(sha256.New, []byte(envValue), nil, []byte("switchboard-api-key-encryption-v1"))
|
||||
hkdfReader := hkdf.New(sha256.New, []byte(envValue), nil, []byte("armature-api-key-encryption-v1"))
|
||||
key := make([]byte, 32)
|
||||
if _, err := io.ReadFull(hkdfReader, key); err != nil {
|
||||
return nil, fmt.Errorf("HKDF derivation failed: %w", err)
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
_ "github.com/lib/pq"
|
||||
_ "modernc.org/sqlite"
|
||||
|
||||
"switchboard-core/config"
|
||||
"armature/config"
|
||||
)
|
||||
|
||||
// DB is the application-wide database connection pool.
|
||||
@@ -80,7 +80,7 @@ func connectPostgres(dsn string) error {
|
||||
// connectSQLite opens a SQLite database with WAL mode enabled.
|
||||
func connectSQLite(dsn string) error {
|
||||
if dsn == "" {
|
||||
dsn = "switchboard.db"
|
||||
dsn = "armature.db"
|
||||
}
|
||||
|
||||
// Ensure parent directory exists for file-based DBs.
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
// Use SetupTestDB in TestMain and pass this to subtests.
|
||||
var TestDB *sql.DB
|
||||
|
||||
const testDBName = "switchboard_core_ci"
|
||||
const testDBName = "armature_ci"
|
||||
|
||||
// SetupTestDB connects to the appropriate database backend (Postgres or
|
||||
// SQLite based on DB_DRIVER env), runs migrations, and sets database.DB
|
||||
@@ -50,7 +50,7 @@ func setupSQLiteTestDB() func() {
|
||||
CurrentDialect = DialectSQLite
|
||||
|
||||
// Use a temp file so multiple connections share the same DB.
|
||||
tmpFile, err := os.CreateTemp("", "switchboard-test-*.db")
|
||||
tmpFile, err := os.CreateTemp("", "armature-test-*.db")
|
||||
if err != nil {
|
||||
log.Printf("⚠ Cannot create temp SQLite DB: %v — skipping DB tests", err)
|
||||
return func() {}
|
||||
@@ -337,7 +337,7 @@ func TruncateAll(t *testing.T) {
|
||||
DB.Exec(`
|
||||
INSERT INTO global_settings (key, value) VALUES
|
||||
('registration', '{"enabled": true}'),
|
||||
('site', '{"name": "Switchboard Core", "tagline": "Self-hosted extension platform"}'),
|
||||
('site', '{"name": "Armature", "tagline": "Self-hosted extension platform"}'),
|
||||
('banner', '{"enabled": false, "text": "", "bg": "#007a33", "fg": "#ffffff"}')
|
||||
ON CONFLICT (key) DO NOTHING
|
||||
`)
|
||||
@@ -351,7 +351,7 @@ func TruncateAll(t *testing.T) {
|
||||
DB.Exec(`
|
||||
INSERT INTO global_settings (key, value) VALUES
|
||||
('registration', '{"enabled": true}'::jsonb),
|
||||
('site', '{"name": "Switchboard Core", "tagline": "Self-hosted extension platform"}'::jsonb),
|
||||
('site', '{"name": "Armature", "tagline": "Self-hosted extension platform"}'::jsonb),
|
||||
('banner', '{"enabled": false, "text": "", "bg": "#007a33", "fg": "#ffffff"}'::jsonb)
|
||||
ON CONFLICT (key) DO NOTHING
|
||||
`)
|
||||
|
||||
@@ -23,10 +23,10 @@ import (
|
||||
|
||||
"github.com/lib/pq"
|
||||
|
||||
"switchboard-core/database"
|
||||
"armature/database"
|
||||
)
|
||||
|
||||
const pgNotifyChannel = "switchboard_events"
|
||||
const pgNotifyChannel = "armature_events"
|
||||
|
||||
// maxNotifyBytes is the practical PG NOTIFY payload limit (8192 byte hard limit,
|
||||
// leave headroom for encoding overhead).
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// TicketValidatorAdapter satisfies middleware.TicketValidator using a
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
|
||||
"switchboard-core/metrics"
|
||||
"armature/metrics"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module switchboard-core
|
||||
module armature
|
||||
|
||||
go 1.23.0
|
||||
|
||||
@@ -14,7 +14,7 @@ require (
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
go.starlark.net v0.0.0-20260210143700-b62fd896b91b
|
||||
golang.org/x/crypto v0.41.0
|
||||
golang.org/x/net v0.43.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v1.34.5
|
||||
)
|
||||
|
||||
@@ -52,10 +52,10 @@ require (
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/libc v1.55.3 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.8.0 // indirect
|
||||
|
||||
@@ -135,8 +135,6 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
|
||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
|
||||
|
||||
@@ -10,12 +10,12 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"switchboard-core/auth"
|
||||
"switchboard-core/crypto"
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/storage"
|
||||
"switchboard-core/store"
|
||||
"armature/auth"
|
||||
"armature/crypto"
|
||||
"armature/database"
|
||||
"armature/models"
|
||||
"armature/storage"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
type AdminHandler struct {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/models"
|
||||
"armature/models"
|
||||
)
|
||||
|
||||
// ListGlobalConnections returns all global-scope connections.
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/notifications"
|
||||
"switchboard-core/store"
|
||||
"armature/notifications"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// AdminEmailHandler handles admin SMTP configuration and test endpoints.
|
||||
@@ -53,7 +53,7 @@ func (h *AdminEmailHandler) TestEmail(c *gin.Context) {
|
||||
}
|
||||
|
||||
// Get instance name
|
||||
instanceName := "Switchboard Core"
|
||||
instanceName := "Armature"
|
||||
if branding, err := h.stores.GlobalConfig.Get(context.Background(), "branding"); err == nil {
|
||||
if name, ok := branding["instance_name"].(string); ok && name != "" {
|
||||
instanceName = name
|
||||
@@ -64,7 +64,7 @@ func (h *AdminEmailHandler) TestEmail(c *gin.Context) {
|
||||
htmlBody := `<!DOCTYPE html>
|
||||
<html><body style="font-family: sans-serif; padding: 20px;">
|
||||
<h2 style="color: #4a8af4;">` + instanceName + `</h2>
|
||||
<p>This is a test email from your Switchboard Core instance.</p>
|
||||
<p>This is a test email from your Armature instance.</p>
|
||||
<p>If you received this, your SMTP configuration is working correctly.</p>
|
||||
</body></html>`
|
||||
textBody := instanceName + " — Test Email\n\nThis is a test email. Your SMTP configuration is working correctly."
|
||||
|
||||
@@ -3,7 +3,7 @@ package handlers
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/metrics"
|
||||
"armature/metrics"
|
||||
)
|
||||
|
||||
// MetricsHandler serves the admin metrics endpoint.
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/metrics"
|
||||
"switchboard-core/store"
|
||||
"armature/metrics"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// mockHub implements metrics.ConnCounter for tests.
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// AuditLog writes an audit entry via the store interface.
|
||||
|
||||
@@ -17,11 +17,11 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"switchboard-core/auth"
|
||||
"switchboard-core/config"
|
||||
"switchboard-core/crypto"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/auth"
|
||||
"armature/config"
|
||||
"armature/crypto"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// Claims represents the JWT payload.
|
||||
@@ -517,7 +517,7 @@ func BootstrapAdmin(cfg *config.Config, s store.Stores, uekCache ...*crypto.UEKC
|
||||
|
||||
email := cfg.AdminEmail
|
||||
if email == "" {
|
||||
email = cfg.AdminUsername + "@switchboard.local"
|
||||
email = cfg.AdminUsername + "@armature.local"
|
||||
}
|
||||
|
||||
handle := auth.UniqueHandle(ctx, s.Users, models.HandleFromName(cfg.AdminUsername))
|
||||
@@ -612,7 +612,7 @@ func SeedUsers(cfg *config.Config, s store.Stores, uekCache ...*crypto.UEKCache)
|
||||
handle := auth.UniqueHandle(ctx, s.Users, models.HandleFromName(username))
|
||||
user := &models.User{
|
||||
Username: username,
|
||||
Email: username + "@switchboard.local",
|
||||
Email: username + "@armature.local",
|
||||
PasswordHash: string(hash),
|
||||
IsActive: true,
|
||||
AuthSource: "builtin",
|
||||
|
||||
@@ -14,9 +14,9 @@ import (
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"switchboard-core/auth"
|
||||
"switchboard-core/config"
|
||||
"switchboard-core/store"
|
||||
"armature/auth"
|
||||
"armature/config"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
func testConfig() *config.Config {
|
||||
@@ -43,7 +43,7 @@ func TestJWTGeneration(t *testing.T) {
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
IssuedAt: jwt.NewNumericDate(now),
|
||||
ExpiresAt: jwt.NewNumericDate(now.Add(15 * time.Minute)),
|
||||
Issuer: "switchboard-core",
|
||||
Issuer: "armature",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/store"
|
||||
"armature/database"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// BackupHandler provides backup/restore endpoints for admin users.
|
||||
@@ -101,7 +101,7 @@ func (h *BackupHandler) CreateBackup(c *gin.Context) {
|
||||
}
|
||||
|
||||
// Stream directly to client
|
||||
filename := fmt.Sprintf("switchboard-%s-%s.swb", meta.Version, meta.Timestamp.Format("20060102-150405"))
|
||||
filename := fmt.Sprintf("armature-%s-%s.swb", meta.Version, meta.Timestamp.Format("20060102-150405"))
|
||||
c.Header("Content-Type", "application/zip")
|
||||
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%q", filename))
|
||||
|
||||
@@ -119,7 +119,7 @@ func (h *BackupHandler) createStoredBackup(c *gin.Context, ctx interface{ Deadli
|
||||
}
|
||||
os.MkdirAll(dir, 0755)
|
||||
|
||||
filename := fmt.Sprintf("switchboard-%s-%s.swb", meta.Version, meta.Timestamp.Format("20060102-150405"))
|
||||
filename := fmt.Sprintf("armature-%s-%s.swb", meta.Version, meta.Timestamp.Format("20060102-150405"))
|
||||
path := filepath.Join(dir, filename)
|
||||
|
||||
f, err := os.Create(path)
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"switchboard-core/database"
|
||||
"armature/database"
|
||||
)
|
||||
|
||||
// coreTableOrder lists tables for backup in FK-safe import order.
|
||||
|
||||
@@ -13,12 +13,12 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
authpkg "switchboard-core/auth"
|
||||
"switchboard-core/config"
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/middleware"
|
||||
"switchboard-core/store"
|
||||
"switchboard-core/store/sqlite"
|
||||
authpkg "armature/auth"
|
||||
"armature/config"
|
||||
"armature/database"
|
||||
"armature/middleware"
|
||||
"armature/store"
|
||||
"armature/store/sqlite"
|
||||
)
|
||||
|
||||
// ── Backup Test Harness ────────────────────────
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ClusterHandler serves the admin cluster API.
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// mockClusterStore implements store.ClusterStore for handler tests.
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"switchboard-core/crypto"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/crypto"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ConnectionResolverAdapter implements sandbox.ConnectionResolver.
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ConnectionTypeEntry is a single connection type in the API response.
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/crypto"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/crypto"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ConnectionHandler handles user-facing extension connection endpoints.
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/models"
|
||||
"armature/models"
|
||||
)
|
||||
|
||||
// ── Extension Dependencies ──────────────────
|
||||
|
||||
@@ -41,9 +41,9 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.starlark.net/starlark"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/sandbox"
|
||||
"switchboard-core/store"
|
||||
"armature/models"
|
||||
"armature/sandbox"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ExtAPIHandler serves extension API routes via Starlark.
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// validSchemaIdentifier matches safe SQL identifiers for table and column names.
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ── mock ExtDataStore ────────────────────────────────────────────────────────
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ExtPermHandler serves extension permission management endpoints.
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ExtSecretsHandler serves extension secret management endpoints.
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
authpkg "switchboard-core/auth"
|
||||
"switchboard-core/config"
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/middleware"
|
||||
"switchboard-core/store"
|
||||
postgres "switchboard-core/store/postgres"
|
||||
sqlite "switchboard-core/store/sqlite"
|
||||
authpkg "armature/auth"
|
||||
"armature/config"
|
||||
"armature/database"
|
||||
"armature/middleware"
|
||||
"armature/store"
|
||||
postgres "armature/store/postgres"
|
||||
sqlite "armature/store/sqlite"
|
||||
)
|
||||
|
||||
// ── Extension Test Harness ──────────────────
|
||||
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
|
||||
"strings"
|
||||
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"switchboard-core/triggers"
|
||||
"armature/database"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
"armature/triggers"
|
||||
)
|
||||
|
||||
// ExtensionHandler serves extension management endpoints.
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/auth"
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/notifications"
|
||||
"switchboard-core/store"
|
||||
"armature/auth"
|
||||
"armature/database"
|
||||
"armature/models"
|
||||
"armature/notifications"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ── Request types ───────────────────────────
|
||||
|
||||
@@ -8,14 +8,14 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/config"
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/middleware"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/notifications"
|
||||
"switchboard-core/store"
|
||||
postgres "switchboard-core/store/postgres"
|
||||
sqlite "switchboard-core/store/sqlite"
|
||||
"armature/config"
|
||||
"armature/database"
|
||||
"armature/middleware"
|
||||
"armature/models"
|
||||
"armature/notifications"
|
||||
"armature/store"
|
||||
postgres "armature/store/postgres"
|
||||
sqlite "armature/store/sqlite"
|
||||
)
|
||||
|
||||
// ── Notification Test Harness ──────────────
|
||||
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/events"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/notifications"
|
||||
"switchboard-core/store"
|
||||
"armature/events"
|
||||
"armature/models"
|
||||
"armature/notifications"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ── Handler ─────────────────────────────────
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@@ -5,17 +5,17 @@ import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/store"
|
||||
postgres "switchboard-core/store/postgres"
|
||||
sqlite "switchboard-core/store/sqlite"
|
||||
"armature/database"
|
||||
"armature/store"
|
||||
postgres "armature/store/postgres"
|
||||
sqlite "armature/store/sqlite"
|
||||
)
|
||||
|
||||
// Minimal static spec for testing — valid OpenAPI 3.0 structure.
|
||||
var testStaticSpec = []byte(`
|
||||
openapi: "3.0.3"
|
||||
info:
|
||||
title: Switchboard Core
|
||||
title: Armature
|
||||
version: "${VERSION}"
|
||||
paths:
|
||||
/api/v1/health:
|
||||
|
||||
@@ -8,13 +8,13 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
authpkg "switchboard-core/auth"
|
||||
"switchboard-core/config"
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/middleware"
|
||||
"switchboard-core/store"
|
||||
postgres "switchboard-core/store/postgres"
|
||||
sqlite "switchboard-core/store/sqlite"
|
||||
authpkg "armature/auth"
|
||||
"armature/config"
|
||||
"armature/database"
|
||||
"armature/middleware"
|
||||
"armature/store"
|
||||
postgres "armature/store/postgres"
|
||||
sqlite "armature/store/sqlite"
|
||||
)
|
||||
|
||||
// ── Dormant Test Harness ──────────────────────
|
||||
|
||||
@@ -29,7 +29,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// RegistryEntry represents a single package in the registry.
|
||||
|
||||
@@ -15,11 +15,11 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.starlark.net/starlark"
|
||||
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/sandbox"
|
||||
"switchboard-core/store"
|
||||
"switchboard-core/triggers"
|
||||
"armature/database"
|
||||
"armature/models"
|
||||
"armature/sandbox"
|
||||
"armature/store"
|
||||
"armature/triggers"
|
||||
)
|
||||
|
||||
// validPackageID matches lowercase alphanumeric slugs with optional hyphens.
|
||||
|
||||
@@ -15,11 +15,11 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/sandbox"
|
||||
"switchboard-core/store"
|
||||
"switchboard-core/triggers"
|
||||
"armature/database"
|
||||
"armature/models"
|
||||
"armature/sandbox"
|
||||
"armature/store"
|
||||
"armature/triggers"
|
||||
)
|
||||
|
||||
// defaultBundledPackages is the curated set of packages installed by default.
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/store"
|
||||
postgres "switchboard-core/store/postgres"
|
||||
sqlite "switchboard-core/store/sqlite"
|
||||
"armature/database"
|
||||
"armature/store"
|
||||
postgres "armature/store/postgres"
|
||||
sqlite "armature/store/sqlite"
|
||||
)
|
||||
|
||||
// ── Test helpers ──────────────────────────────
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/store"
|
||||
"armature/database"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ── Helpers ────────────────────────────────────
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
const presenceOnlineThreshold = 90 * time.Second
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/auth"
|
||||
"switchboard-core/store"
|
||||
"armature/auth"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ProfileBootstrapHandler serves the combined boot payload.
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/auth"
|
||||
"switchboard-core/store"
|
||||
"armature/auth"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ProfilePermissionsHandler exposes the current user's resolved permissions.
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lib/pq"
|
||||
|
||||
"switchboard-core/database"
|
||||
"armature/database"
|
||||
)
|
||||
|
||||
// ── SafeJSON ────────────────────────────────
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/robfig/cron/v3"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"switchboard-core/triggers"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
"armature/triggers"
|
||||
)
|
||||
|
||||
// ScheduleHandler provides CRUD for user-created scheduled tasks.
|
||||
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"switchboard-core/crypto"
|
||||
"switchboard-core/store"
|
||||
"armature/crypto"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ── Request Types ───────────────────────────
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/storage"
|
||||
"armature/storage"
|
||||
)
|
||||
|
||||
// storageConfigured is a package-level flag set during init.
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/models"
|
||||
"armature/models"
|
||||
)
|
||||
|
||||
// ListTeamConnections returns connections scoped to a team.
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// TeamPackageSettingsHandler serves team-scoped package settings endpoints.
|
||||
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/crypto"
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/crypto"
|
||||
"armature/database"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ── Request types ───────────────────────────
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"switchboard-core/database"
|
||||
"armature/database"
|
||||
)
|
||||
|
||||
const testJWTSecret = "test-secret-key-for-handler-tests"
|
||||
@@ -48,7 +48,7 @@ func makeToken(userID, email, _ string) string {
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(15 * time.Minute)),
|
||||
Issuer: "switchboard-core",
|
||||
Issuer: "armature",
|
||||
},
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/database"
|
||||
"armature/database"
|
||||
|
||||
_ "modernc.org/sqlite" // register sqlite driver for DB_DRIVER=sqlite
|
||||
)
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"switchboard-core/triggers"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
"armature/triggers"
|
||||
)
|
||||
|
||||
// manifestTrigger is the manifest.json trigger declaration shape.
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"switchboard-core/triggers"
|
||||
"armature/store"
|
||||
"armature/triggers"
|
||||
)
|
||||
|
||||
// TriggerHandler provides admin CRUD for extension-declared triggers.
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/database"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ═══════════════════════════════════════════════
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// allowedNonGlobalPermissions is the set of permissions that non-admin
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"switchboard-core/workflow"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
"armature/workflow"
|
||||
)
|
||||
|
||||
// ── Assignment Handlers ─────────────────────
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/workflow"
|
||||
"armature/database"
|
||||
"armature/models"
|
||||
"armature/workflow"
|
||||
)
|
||||
|
||||
// testEngine creates a workflow engine with nil bus and runner (safe for tests).
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
|
||||
"go.starlark.net/starlark"
|
||||
|
||||
"switchboard-core/sandbox"
|
||||
"switchboard-core/store"
|
||||
"armature/sandbox"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ── on_advance Hook ─────────────────────────
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"switchboard-core/workflow"
|
||||
"armature/store"
|
||||
"armature/workflow"
|
||||
)
|
||||
|
||||
// ── Instance Handlers ───────────────────────
|
||||
|
||||
@@ -15,8 +15,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// WorkflowPackageHandler handles workflow package export and install.
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"switchboard-core/workflow"
|
||||
"armature/store"
|
||||
"armature/workflow"
|
||||
)
|
||||
|
||||
// ── Public Workflow Handlers ───────
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"switchboard-core/workflow"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
"armature/workflow"
|
||||
)
|
||||
|
||||
// ── Signoff Handlers ─────────────────
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"switchboard-core/store/postgres"
|
||||
"switchboard-core/store/sqlite"
|
||||
"armature/database"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
"armature/store/postgres"
|
||||
"armature/store/sqlite"
|
||||
)
|
||||
|
||||
// jsonEq compares two JSON byte slices ignoring whitespace and key order
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/models"
|
||||
"armature/models"
|
||||
)
|
||||
|
||||
// ── Team-Scoped Workflow Wrappers ────────────────
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ── Workflow Handler ────────────────────────
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Package logging provides structured logging configuration for
|
||||
// Switchboard Core using the standard library's log/slog package.
|
||||
// Armature using the standard library's log/slog package.
|
||||
// Configured via LOG_FORMAT ("text"|"json") and LOG_LEVEL env vars.
|
||||
package logging
|
||||
|
||||
|
||||
@@ -15,25 +15,25 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
|
||||
"switchboard-core/auth"
|
||||
"switchboard-core/cluster"
|
||||
"switchboard-core/config"
|
||||
"switchboard-core/crypto"
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/events"
|
||||
"switchboard-core/sandbox"
|
||||
"switchboard-core/handlers"
|
||||
"switchboard-core/logging"
|
||||
"switchboard-core/metrics"
|
||||
"switchboard-core/middleware"
|
||||
"switchboard-core/notifications"
|
||||
"switchboard-core/pages"
|
||||
"switchboard-core/storage"
|
||||
"switchboard-core/store"
|
||||
"switchboard-core/triggers"
|
||||
"switchboard-core/workflow"
|
||||
postgres "switchboard-core/store/postgres"
|
||||
sqliteStore "switchboard-core/store/sqlite"
|
||||
"armature/auth"
|
||||
"armature/cluster"
|
||||
"armature/config"
|
||||
"armature/crypto"
|
||||
"armature/database"
|
||||
"armature/events"
|
||||
"armature/sandbox"
|
||||
"armature/handlers"
|
||||
"armature/logging"
|
||||
"armature/metrics"
|
||||
"armature/middleware"
|
||||
"armature/notifications"
|
||||
"armature/pages"
|
||||
"armature/storage"
|
||||
"armature/store"
|
||||
"armature/triggers"
|
||||
"armature/workflow"
|
||||
postgres "armature/store/postgres"
|
||||
sqliteStore "armature/store/sqlite"
|
||||
)
|
||||
|
||||
//
|
||||
@@ -45,13 +45,13 @@ var swaggerHTML []byte
|
||||
|
||||
func main() {
|
||||
// ── Subcommand dispatch ──────────────────
|
||||
// Usage: switchboard vault rekey
|
||||
// Usage: armature vault rekey
|
||||
if len(os.Args) > 2 && os.Args[1] == "vault" {
|
||||
runVaultCommand(os.Args[2])
|
||||
return
|
||||
}
|
||||
if len(os.Args) > 1 && os.Args[1] == "version" {
|
||||
fmt.Println("switchboard", Version)
|
||||
fmt.Println("armature", Version)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ func main() {
|
||||
if stores.GlobalConfig != nil {
|
||||
if smtpCfg, err := notifications.LoadSMTPConfig(stores.GlobalConfig, keyResolver); err == nil && smtpCfg != nil {
|
||||
transport := notifications.NewEmailTransport(*smtpCfg)
|
||||
instanceName := "Switchboard Core"
|
||||
instanceName := "Armature"
|
||||
if brandCfg, err := stores.GlobalConfig.Get(context.Background(), "branding"); err == nil {
|
||||
if name, ok := brandCfg["instance_name"].(string); ok && name != "" {
|
||||
instanceName = name
|
||||
@@ -899,7 +899,7 @@ func main() {
|
||||
if bp == "" {
|
||||
bp = "/"
|
||||
}
|
||||
log.Printf("🔀 Switchboard Core v%s starting on port %s", Version, cfg.Port)
|
||||
log.Printf("⚙ Armature v%s starting on port %s", Version, cfg.Port)
|
||||
log.Printf(" Base path: %s", bp)
|
||||
log.Printf(" Schema: %s", database.SchemaVersion())
|
||||
if objStore != nil {
|
||||
@@ -1014,7 +1014,7 @@ func runVaultCommand(subcmd string) {
|
||||
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "Unknown vault command: %s\n", subcmd)
|
||||
fmt.Fprintf(os.Stderr, "Usage: switchboard vault <rekey|status>\n")
|
||||
fmt.Fprintf(os.Stderr, "Usage: armature vault <rekey|status>\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/store"
|
||||
"armature/database"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// Snapshot is the top-level JSON response from GET /api/v1/admin/metrics.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Package metrics defines all Prometheus metrics for Switchboard Core.
|
||||
// All metrics use the "switchboard_" prefix. Registered via promauto
|
||||
// Package metrics defines all Prometheus metrics for Armature Core.
|
||||
// All metrics use the "armature_" prefix. Registered via promauto
|
||||
// so they are available on the default registry's /metrics endpoint.
|
||||
package metrics
|
||||
|
||||
@@ -12,12 +12,12 @@ import (
|
||||
|
||||
var (
|
||||
HTTPRequestsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "switchboard_http_requests_total",
|
||||
Name: "armature_http_requests_total",
|
||||
Help: "Total HTTP requests by method, path pattern, and status code.",
|
||||
}, []string{"method", "path_pattern", "status"})
|
||||
|
||||
HTTPRequestDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Name: "switchboard_http_request_duration_seconds",
|
||||
Name: "armature_http_request_duration_seconds",
|
||||
Help: "HTTP request latency in seconds.",
|
||||
Buckets: []float64{0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30},
|
||||
}, []string{"method", "path_pattern"})
|
||||
@@ -26,7 +26,7 @@ var (
|
||||
// ── WebSocket Metrics ───────────────────────
|
||||
|
||||
var WebSocketConnections = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "switchboard_websocket_connections",
|
||||
Name: "armature_websocket_connections",
|
||||
Help: "Current number of active WebSocket connections.",
|
||||
})
|
||||
|
||||
@@ -34,17 +34,17 @@ var WebSocketConnections = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
|
||||
var (
|
||||
CompletionTokensTotal = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "switchboard_completion_tokens_total",
|
||||
Name: "armature_completion_tokens_total",
|
||||
Help: "Total tokens processed by direction (prompt|completion) and model.",
|
||||
}, []string{"direction", "model_id"})
|
||||
|
||||
CompletionsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "switchboard_completions_total",
|
||||
Name: "armature_completions_total",
|
||||
Help: "Total completion requests by provider, model, and status.",
|
||||
}, []string{"provider_config_id", "model_id", "status"})
|
||||
|
||||
CompletionDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Name: "switchboard_completion_duration_seconds",
|
||||
Name: "armature_completion_duration_seconds",
|
||||
Help: "Completion request latency (wall time including tool loops).",
|
||||
Buckets: []float64{0.1, 0.5, 1, 2, 5, 10, 30, 60, 120},
|
||||
}, []string{"provider_config_id", "model_id"})
|
||||
@@ -53,7 +53,7 @@ var (
|
||||
// ── Provider Health ─────────────────────────
|
||||
|
||||
var ProviderStatus = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Name: "switchboard_provider_status",
|
||||
Name: "armature_provider_status",
|
||||
Help: "Provider health status: 0=unknown, 1=healthy, 2=degraded, 3=down.",
|
||||
}, []string{"provider_config_id"})
|
||||
|
||||
@@ -61,23 +61,23 @@ var ProviderStatus = promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
|
||||
var (
|
||||
DBOpenConnections = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "switchboard_db_open_connections",
|
||||
Name: "armature_db_open_connections",
|
||||
Help: "Number of open database connections.",
|
||||
})
|
||||
DBInUseConnections = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "switchboard_db_in_use_connections",
|
||||
Name: "armature_db_in_use_connections",
|
||||
Help: "Number of database connections currently in use.",
|
||||
})
|
||||
DBIdleConnections = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "switchboard_db_idle_connections",
|
||||
Name: "armature_db_idle_connections",
|
||||
Help: "Number of idle database connections.",
|
||||
})
|
||||
DBWaitCount = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "switchboard_db_wait_count_total",
|
||||
Name: "armature_db_wait_count_total",
|
||||
Help: "Total number of connections waited for.",
|
||||
})
|
||||
DBWaitDuration = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "switchboard_db_wait_duration_seconds_total",
|
||||
Name: "armature_db_wait_duration_seconds_total",
|
||||
Help: "Total time blocked waiting for a new connection (seconds).",
|
||||
})
|
||||
)
|
||||
@@ -85,13 +85,13 @@ var (
|
||||
// ── Task Scheduler Metrics ──────────────────
|
||||
|
||||
var TaskExecutionsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "switchboard_task_executions_total",
|
||||
Name: "armature_task_executions_total",
|
||||
Help: "Total task executions by status (success|error).",
|
||||
}, []string{"status"})
|
||||
|
||||
// ── Sandbox Metrics ─────────────────────────
|
||||
|
||||
var SandboxExecutionsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "switchboard_sandbox_executions_total",
|
||||
Name: "armature_sandbox_executions_total",
|
||||
Help: "Total Starlark sandbox executions by entry point and status.",
|
||||
}, []string{"entry_point", "status"})
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/auth"
|
||||
"switchboard-core/store"
|
||||
"armature/auth"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// RequireAdmin returns middleware that restricts access to users with the
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
|
||||
"switchboard-core/config"
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/store"
|
||||
"armature/config"
|
||||
"armature/database"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// Claims represents the JWT payload. Must match handlers.Claims.
|
||||
|
||||
@@ -7,10 +7,10 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/auth"
|
||||
"switchboard-core/config"
|
||||
"switchboard-core/database"
|
||||
"switchboard-core/store"
|
||||
"armature/auth"
|
||||
"armature/config"
|
||||
"armature/database"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// AuthOrRedirect validates JWT tokens for page routes.
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/auth"
|
||||
"switchboard-core/store"
|
||||
"armature/auth"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
const permCacheKey = "resolved_permissions"
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/metrics"
|
||||
"armature/metrics"
|
||||
)
|
||||
|
||||
// Prometheus returns a Gin middleware that records HTTP request metrics.
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// RateLimiter implements per-IP rate limiting backed by a shared store.
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// RequireTeamAdmin returns middleware that restricts access to team admins.
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"switchboard-core/store"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// SMTPConfig holds SMTP connection settings, loaded from platform_settings.
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"switchboard-core/events"
|
||||
"switchboard-core/models"
|
||||
"switchboard-core/store"
|
||||
"armature/events"
|
||||
"armature/models"
|
||||
"armature/store"
|
||||
)
|
||||
|
||||
// ── Package-level singleton ─────────────────
|
||||
@@ -53,7 +53,7 @@ func NewService(s store.NotificationStore, hub *events.Hub) *Service {
|
||||
return &Service{
|
||||
store: s,
|
||||
hub: hub,
|
||||
instanceName: "Switchboard Core",
|
||||
instanceName: "Armature",
|
||||
retentionDays: 90,
|
||||
stopCleanup: make(chan struct{}),
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"switchboard-core/models"
|
||||
"armature/models"
|
||||
)
|
||||
|
||||
// mockPrefStore implements store.NotificationPreferenceStore for testing.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user