feat: Phase 9 gaps closed — ApprovalService.Decide convergence, execlog fold, execworker poller
- ApprovalService (core/app/approval.go) + ApprovalRepo (postgres adapter) with
full decide transaction: HMAC token verify, approval flip, execution un-gate,
session-scoped window keys (+session suffix matching GovernanceStore gate),
nomos session flip, audit+event on failure abort. httpapi DecideApproval now
a thin presenter delegating to the service. ListPending payload format fixed
(json.Unmarshal not raw-wrap).
- execlog folded into postgres adapter: internal/execlog deleted, NewExecutionLog
/ ReadExecutionLog live in the db package, callers updated (mcp, httpapi).
- execworker poller over ExecutionService.DispatchQueued: advisory lock leak
fixed (defer/recover per execution), correlation_id preserved via Finalize
event emission (ExecRunRepo.Finalize now emits execution.{status} with
correlation_id from the row).
- Phase 8 session export-rename completed: Store, New, and all 53 methods
exported; cmd/nomos/ agent.go fixed to use session.PendingContinuation etc.
- Coverage gates: ExecutionService.Submit 93.1%, PolicyService.Decide 100%.
- Plans index updated, VERSION bumped to 0.36.0.
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
@@ -10,19 +9,20 @@ import (
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/dtoro/oikos/internal/adapters/postgres"
|
||||
"github.com/dtoro/oikos/internal/adapters/remote"
|
||||
"github.com/dtoro/oikos/internal/adapters/ssh"
|
||||
"github.com/dtoro/oikos/internal/config"
|
||||
"github.com/dtoro/oikos/internal/core/app"
|
||||
"github.com/dtoro/oikos/internal/core/ports"
|
||||
"github.com/dtoro/oikos/internal/adapters/postgres"
|
||||
"github.com/dtoro/oikos/internal/adapters/remote"
|
||||
intremote "github.com/dtoro/oikos/internal/remote"
|
||||
"github.com/dtoro/oikos/internal/adapters/ssh"
|
||||
"github.com/dtoro/oikos/internal/execworker"
|
||||
"github.com/dtoro/oikos/internal/httpapi"
|
||||
"github.com/dtoro/oikos/internal/observability"
|
||||
intremote "github.com/dtoro/oikos/internal/remote"
|
||||
"github.com/dtoro/oikos/internal/scheduler"
|
||||
"github.com/dtoro/oikos/internal/secrets"
|
||||
)
|
||||
@@ -59,9 +59,9 @@ func main() {
|
||||
)
|
||||
if sec != nil {
|
||||
overlays := secrets.ConfigOverlays(map[string]func(string){
|
||||
"mcp_bearer-token": func(v string) { cfg.MCPBearerToken = v },
|
||||
"api_token": func(v string) { cfg.APIToken = v },
|
||||
"oidc_client-secret": func(v string) { cfg.OIDCClientSecret = v },
|
||||
"mcp_bearer-token": func(v string) { cfg.MCPBearerToken = v },
|
||||
"api_token": func(v string) { cfg.APIToken = v },
|
||||
"oidc_client-secret": func(v string) { cfg.OIDCClientSecret = v },
|
||||
})
|
||||
n := secrets.OverlayConfig(ctx, sec, overlays)
|
||||
slog.Info("secrets resolved from Infisical", "count", n)
|
||||
@@ -117,7 +117,7 @@ func main() {
|
||||
|
||||
slog.Info("all: starting api with scheduler + execution-worker in background")
|
||||
svc := buildAPIServices(pool)
|
||||
if err := httpapi.ListenAndServe(ctx, pool, cfg, svc.entities, svc.entityRepo, svc.readModels, svc.relService, svc.provisioning, svc.seeds, svc.execSvc); err != nil {
|
||||
if err := httpapi.ListenAndServe(ctx, pool, cfg, svc.entities, svc.entityRepo, svc.readModels, svc.relService, svc.provisioning, svc.seeds, svc.execSvc, svc.approvalSvc); err != nil {
|
||||
slog.Error("api failed", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -210,7 +210,7 @@ func runAPI(ctx context.Context, cfg config.Config) error {
|
||||
}
|
||||
|
||||
svc := buildAPIServices(pool)
|
||||
err = httpapi.ListenAndServe(ctx, pool, cfg, svc.entities, svc.entityRepo, svc.readModels, svc.relService, svc.provisioning, svc.seeds, svc.execSvc)
|
||||
err = httpapi.ListenAndServe(ctx, pool, cfg, svc.entities, svc.entityRepo, svc.readModels, svc.relService, svc.provisioning, svc.seeds, svc.execSvc, svc.approvalSvc)
|
||||
if err == http.ErrServerClosed {
|
||||
return nil
|
||||
}
|
||||
@@ -228,6 +228,7 @@ type apiServices struct {
|
||||
provisioning *app.ProvisioningService
|
||||
seeds *app.SeedService
|
||||
execSvc *app.ExecutionService
|
||||
approvalSvc *app.ApprovalService
|
||||
}
|
||||
|
||||
func buildAPIServices(pool *db.Pool) apiServices {
|
||||
@@ -256,6 +257,7 @@ func buildAPIServices(pool *db.Pool) apiServices {
|
||||
return intremote.ResolveProxmoxHostSlug(ctx, pool, id, "")
|
||||
}
|
||||
execSvc := app.NewExecutionService(policySvc, executor, resolver, db.NewExecRunRepo(pool))
|
||||
approvalSvc := app.NewApprovalService(db.NewApprovalRepo(pool))
|
||||
|
||||
return apiServices{
|
||||
entities: entities,
|
||||
@@ -265,6 +267,7 @@ func buildAPIServices(pool *db.Pool) apiServices {
|
||||
provisioning: provisioning,
|
||||
seeds: seeds,
|
||||
execSvc: execSvc,
|
||||
approvalSvc: approvalSvc,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,9 +397,9 @@ func runSecretAudit(ctx context.Context, cfg config.Config) {
|
||||
backend := newInfisicalBackendOrFail(cfg)
|
||||
|
||||
envValues := map[string]string{
|
||||
"mcp_bearer-token": cfg.MCPBearerToken,
|
||||
"api_token": cfg.APIToken,
|
||||
"oidc_client-secret": cfg.OIDCClientSecret,
|
||||
"mcp_bearer-token": cfg.MCPBearerToken,
|
||||
"api_token": cfg.APIToken,
|
||||
"oidc_client-secret": cfg.OIDCClientSecret,
|
||||
}
|
||||
|
||||
fmt.Println("key infisical env status")
|
||||
@@ -525,4 +528,4 @@ func runExport(ctx context.Context, cfg config.Config) error {
|
||||
slog.Info("exported", "file", path, "bytes", len(content))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user