feat: Phase 4 governance/execution slice — PolicyService + ExecutionService
classifyAndGate's decision pipeline moves to core: PolicyService runs the full gate order (classify + transport escalation, plan-first, syntax, host-only/host-lxc, VM QGA preflight, dedup, approval-flood, window routing) over ports.GovernanceStore; ExecutionService records and dispatches (auto-run via ssh.CommandExecutor + TargetResolver, queue via ExecutionRecorder) with one converged path for run/docker_exec. Gating matrix test added (risk x window x declared risk -> outcome); pair coverage 95.6%. Bug fix surfaced by the matrix: the flag-space syntax regex was inverted — it refused valid 'tail -n 3' and missed the actual 'head - n' typo. Fixed to match dash-space-value only. Remaining Phase 4 items tracked in the plan: ApprovalService.Decide convergence, execlog fold, execworker poller. VERSION 0.35.0.
This commit is contained in:
@@ -74,6 +74,9 @@ type Server struct {
|
||||
provisioning *app.ProvisioningService
|
||||
// seeds regenerates seed YAMLs for the export endpoint (Phase 7).
|
||||
seeds *app.SeedService
|
||||
// execSvc is the run-submission use-case (Phase 4): PolicyService
|
||||
// gating + auto-run/queue dispatch, shared by the MCP tools.
|
||||
execSvc *app.ExecutionService
|
||||
}
|
||||
|
||||
// NewHandler builds the full HTTP handler: /healthz (unauthenticated,
|
||||
@@ -83,7 +86,7 @@ type Server struct {
|
||||
// holds a dedicated pooled connection for LISTEN. Callers MUST cancel ctx
|
||||
// before closing the pool — otherwise the held connection never releases
|
||||
// and pool.Close() deadlocks.
|
||||
func NewHandler(ctx context.Context, pool *db.Pool, cfg config.Config, entities *app.EntityService, entityRepo *db.EntityRepo, readModels ports.ReadModels, relService *app.RelationshipService, provisioning *app.ProvisioningService, seeds *app.SeedService) http.Handler {
|
||||
func NewHandler(ctx context.Context, pool *db.Pool, cfg config.Config, entities *app.EntityService, entityRepo *db.EntityRepo, readModels ports.ReadModels, relService *app.RelationshipService, provisioning *app.ProvisioningService, seeds *app.SeedService, execSvc *app.ExecutionService) http.Handler {
|
||||
s := &Server{
|
||||
pool: pool,
|
||||
cfg: cfg,
|
||||
@@ -96,6 +99,7 @@ func NewHandler(ctx context.Context, pool *db.Pool, cfg config.Config, entities
|
||||
relService: relService,
|
||||
provisioning: provisioning,
|
||||
seeds: seeds,
|
||||
execSvc: execSvc,
|
||||
}
|
||||
|
||||
// Wire secrets backend: Infisical primary with SOPS DR fallback.
|
||||
@@ -339,7 +343,7 @@ func NewHandler(ctx context.Context, pool *db.Pool, cfg config.Config, entities
|
||||
if nomosAgentID == uuid.Nil && cfg.NomosAgentSlug != "" {
|
||||
_ = pool.QueryRow(ctx, "SELECT id FROM entities WHERE slug = $1", cfg.NomosAgentSlug).Scan(&nomosAgentID)
|
||||
}
|
||||
r.With(combinedAuth(cfg, false)).Handle("/mcp", mcphandler.NewHandler(pool, cfg.MCPBearerToken, nomosAgentID, s.secretsManager, s.entities, s.relService))
|
||||
r.With(combinedAuth(cfg, false)).Handle("/mcp", mcphandler.NewHandler(pool, cfg.MCPBearerToken, nomosAgentID, s.secretsManager, s.entities, s.relService, s.execSvc))
|
||||
|
||||
if nomosURL := os.Getenv("NOMOS_PROXY_URL"); nomosURL != "" {
|
||||
target, _ := url.Parse(nomosURL)
|
||||
@@ -944,10 +948,10 @@ main();
|
||||
|
||||
// ListenAndServe runs the API server with graceful shutdown on ctx cancel
|
||||
// (SG4): stop accepting, drain in-flight for up to 30s, then exit.
|
||||
func ListenAndServe(ctx context.Context, pool *db.Pool, cfg config.Config, entities *app.EntityService, entityRepo *db.EntityRepo, readModels ports.ReadModels, relService *app.RelationshipService, provisioning *app.ProvisioningService, seeds *app.SeedService) error {
|
||||
func ListenAndServe(ctx context.Context, pool *db.Pool, cfg config.Config, entities *app.EntityService, entityRepo *db.EntityRepo, readModels ports.ReadModels, relService *app.RelationshipService, provisioning *app.ProvisioningService, seeds *app.SeedService, execSvc *app.ExecutionService) error {
|
||||
srv := &http.Server{
|
||||
Addr: cfg.APIListen,
|
||||
Handler: NewHandler(ctx, pool, cfg, entities, entityRepo, readModels, relService, provisioning, seeds),
|
||||
Handler: NewHandler(ctx, pool, cfg, entities, entityRepo, readModels, relService, provisioning, seeds, execSvc),
|
||||
ReadHeaderTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user