feat: implement T-019 reliable event ingress
Harness governance / validate (pull_request) Has been cancelled

This commit is contained in:
QiuSW
2026-08-11 15:41:07 +08:00
parent b7fe44eeb0
commit bd964e8831
33 changed files with 2762 additions and 57 deletions
+85 -10
View File
@@ -11,24 +11,31 @@ import (
"os"
"os/signal"
"path/filepath"
"strings"
"syscall"
"time"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/stdlib"
"yovision/bell/contracts"
"yovision/bell/internal/audit"
"yovision/bell/internal/event"
"yovision/bell/internal/ingress"
"yovision/bell/internal/store"
)
var version = "dev"
type configuration struct {
address string
dsn string
keyFile string
tlsCert string
tlsKey string
address string
dsn string
keyFile string
tlsCert string
tlsKey string
eventIngressEnabled bool
eventKeyFile string
forbiddenNamesFile string
}
func main() {
@@ -41,11 +48,20 @@ func main() {
func loadConfiguration() (configuration, error) {
value := configuration{
address: envOr("BELL_HTTP_ADDR", "127.0.0.1:8081"),
dsn: os.Getenv("BELL_DB_DSN"),
keyFile: os.Getenv("BELL_AUDIT_KEYS_FILE"),
tlsCert: os.Getenv("BELL_TLS_CERT_FILE"),
tlsKey: os.Getenv("BELL_TLS_KEY_FILE"),
address: envOr("BELL_HTTP_ADDR", "127.0.0.1:8081"),
dsn: os.Getenv("BELL_DB_DSN"),
keyFile: os.Getenv("BELL_AUDIT_KEYS_FILE"),
tlsCert: os.Getenv("BELL_TLS_CERT_FILE"),
tlsKey: os.Getenv("BELL_TLS_KEY_FILE"),
eventKeyFile: os.Getenv("BELL_EVENT_INGRESS_KEYS_FILE"),
forbiddenNamesFile: os.Getenv("BELL_EVIDENCE_FORBIDDEN_NAMES_FILE"),
}
switch os.Getenv("BELL_EVENT_INGRESS_ENABLED") {
case "", "false":
case "true":
value.eventIngressEnabled = true
default:
return configuration{}, errors.New("BELL_EVENT_INGRESS_ENABLED must be true or false")
}
if value.dsn == "" {
return configuration{}, errors.New("BELL_DB_DSN is required")
@@ -65,6 +81,14 @@ func loadConfiguration() (configuration, error) {
if (value.tlsCert == "") != (value.tlsKey == "") {
return configuration{}, errors.New("Bell TLS certificate and key must be configured together")
}
if value.eventIngressEnabled {
if value.eventKeyFile == "" || !filepath.IsAbs(value.eventKeyFile) {
return configuration{}, errors.New("BELL_EVENT_INGRESS_KEYS_FILE must be an absolute external path when event ingress is enabled")
}
if value.forbiddenNamesFile == "" || !filepath.IsAbs(value.forbiddenNamesFile) {
return configuration{}, errors.New("BELL_EVIDENCE_FORBIDDEN_NAMES_FILE must be an absolute external path when event ingress is enabled")
}
}
return value, nil
}
@@ -106,6 +130,32 @@ func run(logger *slog.Logger) error {
}
mux := http.NewServeMux()
mux.Handle(audit.RelayPath, handler)
if cfg.eventIngressEnabled {
if err := repository.EventIngressReady(ctx); err != nil {
return err
}
eventKeys, err := ingress.LoadKeys(cfg.eventKeyFile)
if err != nil {
return err
}
forbiddenNames, err := loadForbiddenNames(cfg.forbiddenNamesFile)
if err != nil {
return err
}
guard, err := event.NewEvidenceGuard(forbiddenNames...)
if err != nil {
return err
}
factory, err := event.NewFactory(contracts.EventV01Schema, event.ULIDGenerator{}, repository, guard)
if err != nil {
return err
}
eventHandler, err := ingress.NewHandler(repository, eventKeys, factory)
if err != nil {
return err
}
mux.Handle(ingress.Path, eventHandler)
}
mux.HandleFunc("GET /healthz", func(writer http.ResponseWriter, _ *http.Request) {
writeStatus(writer, http.StatusOK, "ok")
})
@@ -114,6 +164,12 @@ func run(logger *slog.Logger) error {
writeStatus(writer, http.StatusServiceUnavailable, "not_ready")
return
}
if cfg.eventIngressEnabled {
if err := repository.EventIngressReady(request.Context()); err != nil {
writeStatus(writer, http.StatusServiceUnavailable, "not_ready")
return
}
}
writeStatus(writer, http.StatusOK, "ready")
})
server := &http.Server{Addr: cfg.address, Handler: mux, ReadHeaderTimeout: 5 * time.Second, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, TLSConfig: &tls.Config{MinVersion: tls.VersionTLS12}}
@@ -138,6 +194,25 @@ func run(logger *slog.Logger) error {
return server.Shutdown(shutdownContext)
}
func loadForbiddenNames(path string) ([]string, error) {
raw, err := os.ReadFile(path)
if err != nil || len(raw) > 64<<10 {
return nil, errors.New("read Bell evidence forbidden-names file")
}
var values []string
for _, line := range strings.Split(string(raw), "\n") {
line = strings.TrimSpace(line)
if line == "" {
continue
}
values = append(values, line)
}
if len(values) == 0 || len(values) > 256 {
return nil, errors.New("Bell evidence forbidden-names file must contain 1 to 256 names")
}
return values, nil
}
func writeStatus(writer http.ResponseWriter, status int, value string) {
writer.Header().Set("Content-Type", "application/json")
writer.WriteHeader(status)
+20
View File
@@ -31,3 +31,23 @@ func TestConfigurationRequiresTLSOutsideLoopback(t *testing.T) {
t.Fatalf("remote TLS Bell bind rejected: %v", err)
}
}
func TestEventIngressIsDisabledByDefaultAndRequiresExternalPolicy(t *testing.T) {
t.Setenv("BELL_DB_DSN", "postgres://bell@127.0.0.1/yovision")
t.Setenv("BELL_AUDIT_KEYS_FILE", filepath.Join(t.TempDir(), "audit.json"))
t.Setenv("BELL_EVENT_INGRESS_ENABLED", "")
value, err := loadConfiguration()
if err != nil || value.eventIngressEnabled {
t.Fatalf("default event ingress configuration: %+v %v", value, err)
}
t.Setenv("BELL_EVENT_INGRESS_ENABLED", "true")
if _, err := loadConfiguration(); err == nil {
t.Fatal("event ingress without keys and evidence policy was accepted")
}
t.Setenv("BELL_EVENT_INGRESS_KEYS_FILE", filepath.Join(t.TempDir(), "event-keys.json"))
t.Setenv("BELL_EVIDENCE_FORBIDDEN_NAMES_FILE", filepath.Join(t.TempDir(), "names.txt"))
value, err = loadConfiguration()
if err != nil || !value.eventIngressEnabled {
t.Fatalf("valid event ingress configuration rejected: %+v %v", value, err)
}
}