Files
bri-sandbox-development-pla…/control-plane/internal/api/sessions.go
T
Achmad Setyabudi Susilo 3d99940658 Initial SDP skeleton
Sandbox Deployment Platform — Go control plane + agents, NextJS dashboard,
nginx reverse proxy. Cross-compile via Docker; deploy via sshpass to
172.18.136.92 (micro) and 172.18.139.186 (gateway).

- control-plane: HTTP API, WS hub, SQLite (modernc.org/sqlite) for
  progress, .log files for log persistence
- agent-micro / agent-gateway: alpine:3.20 + bind-mounted repo,
  binary exec'd in container, no Dockerfile build step
- dashboard: NextJS static export + shadcn/ui components, single
  WebSocket hook
- docker-compose.yml: three services on alpine:latest with docker
  socket bind for agents
- scripts/: build.sh (golang:1.23-alpine cross-compile), deploy.sh,
  patch-nginx.sh (idempotent nginx splice), ssh wrappers

Runtime model: pass-through Bitbucket creds per deploy, never logged or
persisted on the agent. Control plane never touches git or docker
directly — agents do all the work locally.
2026-06-24 07:25:01 +07:00

46 lines
859 B
Go

package api
import (
"crypto/rand"
"encoding/hex"
"sync"
"time"
)
// Sessions is an in-memory token store. Replace with a signed JWT or
// a Redis-backed store when we need multi-replica CP. For MVP one process
// is enough.
type Sessions struct {
mu sync.RWMutex
store map[string]session
}
type session struct {
user string
expires time.Time
}
func NewSessions() *Sessions {
return &Sessions{store: make(map[string]session)}
}
func (s *Sessions) Issue(user string) string {
b := make([]byte, 16)
_, _ = rand.Read(b)
tok := hex.EncodeToString(b)
s.mu.Lock()
s.store[tok] = session{user: user, expires: time.Now().Add(12 * time.Hour)}
s.mu.Unlock()
return tok
}
func (s *Sessions) Valid(tok string) bool {
s.mu.RLock()
sess, ok := s.store[tok]
s.mu.RUnlock()
if !ok {
return false
}
return time.Now().Before(sess.expires)
}