Publish ITWorx Pulse source
Public source validation / validate (push) Failing after 3m8s

This commit is contained in:
ITWorx Pulse release export
2026-09-03 02:09:19 +02:00
commit bd774932d5
614 changed files with 77116 additions and 0 deletions
+203
View File
@@ -0,0 +1,203 @@
// Package servicedefaults installs the small, explicitly configured service
// monitoring baseline used by a production Pulse deployment.
package servicedefaults
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/url"
"path"
"strings"
"github.com/itworx/pulse/internal/probe"
"github.com/itworx/pulse/internal/reconciliation"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
)
const identityNamespace = "itworx-pulse-service-defaults"
type Options struct {
PublicURL string
OIDCIssuer string
}
type Summary struct {
Services int
Endpoints int
Probes int
Dependencies int
}
type serviceSeed struct {
id, name, description string
endpointID string
endpointName string
endpointType string
target probe.Target
probes []probeSeed
}
type probeSeed struct {
id, name, kind string
target probe.Target
interval int
timeout int
expected []int
verifyTLS bool
}
// Seed validates every configured URL against the same network policy used at
// execution time, then atomically installs or refreshes only Pulse-owned rows.
func Seed(ctx context.Context, pool *pgxpool.Pool, options Options, policy probe.NetworkPolicy, resolver probe.Resolver) (Summary, error) {
if pool == nil {
return Summary{}, errors.New("service defaults require a database pool")
}
seeds, err := desired(ctx, options, policy, resolver)
if err != nil {
return Summary{}, err
}
if len(seeds) == 0 {
return Summary{}, nil
}
tx, err := pool.BeginTx(ctx, pgx.TxOptions{})
if err != nil {
return Summary{}, fmt.Errorf("begin service defaults: %w", err)
}
defer func() { _ = tx.Rollback(ctx) }()
summary := Summary{}
for _, service := range seeds {
labels := []byte(`{"managedBy":"pulse-system-defaults"}`)
if _, err := tx.Exec(ctx, `INSERT INTO services (id,name,description,state,labels,revision)
VALUES ($1,$2,$3,'unknown',$4::jsonb,1)
ON CONFLICT (id) DO UPDATE SET name=EXCLUDED.name,description=EXCLUDED.description,
labels=EXCLUDED.labels,archived_at=NULL,updated_at=now(),revision=services.revision+1
WHERE (services.name,services.description,services.labels,services.archived_at) IS DISTINCT FROM
(EXCLUDED.name,EXCLUDED.description,EXCLUDED.labels,EXCLUDED.archived_at)`,
service.id, service.name, service.description, labels); err != nil {
return Summary{}, fmt.Errorf("upsert system service %q: %w", service.name, err)
}
summary.Services++
target, err := json.Marshal(service.target)
if err != nil {
return Summary{}, fmt.Errorf("encode endpoint target: %w", err)
}
if _, err := tx.Exec(ctx, `INSERT INTO service_endpoints (id,service_id,name,endpoint_type,target,enabled,revision)
VALUES ($1,$2,$3,$4,$5::jsonb,true,1)
ON CONFLICT (id) DO UPDATE SET name=EXCLUDED.name,endpoint_type=EXCLUDED.endpoint_type,
target=EXCLUDED.target,enabled=true,archived_at=NULL,updated_at=now(),revision=service_endpoints.revision+1
WHERE (service_endpoints.name,service_endpoints.endpoint_type,service_endpoints.target,service_endpoints.enabled,service_endpoints.archived_at) IS DISTINCT FROM
(EXCLUDED.name,EXCLUDED.endpoint_type,EXCLUDED.target,EXCLUDED.enabled,EXCLUDED.archived_at)`,
service.endpointID, service.id, service.endpointName, service.endpointType, target); err != nil {
return Summary{}, fmt.Errorf("upsert system endpoint %q: %w", service.endpointName, err)
}
summary.Endpoints++
for _, definition := range service.probes {
target, err := json.Marshal(definition.target)
if err != nil {
return Summary{}, fmt.Errorf("encode probe target: %w", err)
}
expected, err := json.Marshal(definition.expected)
if err != nil {
return Summary{}, fmt.Errorf("encode expected statuses: %w", err)
}
if _, err := tx.Exec(ctx, `INSERT INTO probes
(id,service_id,endpoint_id,name,probe_type,target,interval_seconds,timeout_seconds,enabled,expected_status_codes,follow_redirects,verify_tls,revision)
VALUES ($1,$2,$3,$4,$5,$6::jsonb,$7,$8,true,$9::jsonb,false,$10,1)
ON CONFLICT (id) DO UPDATE SET endpoint_id=EXCLUDED.endpoint_id,name=EXCLUDED.name,
probe_type=EXCLUDED.probe_type,target=EXCLUDED.target,interval_seconds=EXCLUDED.interval_seconds,
timeout_seconds=EXCLUDED.timeout_seconds,enabled=true,expected_status_codes=EXCLUDED.expected_status_codes,
follow_redirects=false,verify_tls=EXCLUDED.verify_tls,archived_at=NULL,updated_at=now(),revision=probes.revision+1
WHERE (probes.endpoint_id,probes.name,probes.probe_type,probes.target,probes.interval_seconds,probes.timeout_seconds,
probes.enabled,probes.expected_status_codes,probes.follow_redirects,probes.verify_tls,probes.archived_at) IS DISTINCT FROM
(EXCLUDED.endpoint_id,EXCLUDED.name,EXCLUDED.probe_type,EXCLUDED.target,EXCLUDED.interval_seconds,EXCLUDED.timeout_seconds,
EXCLUDED.enabled,EXCLUDED.expected_status_codes,EXCLUDED.follow_redirects,EXCLUDED.verify_tls,EXCLUDED.archived_at)`,
definition.id, service.id, service.endpointID, definition.name, definition.kind, target,
definition.interval, definition.timeout, expected, definition.verifyTLS); err != nil {
return Summary{}, fmt.Errorf("upsert system probe %q: %w", definition.name, err)
}
summary.Probes++
}
}
if len(seeds) == 2 {
dependencyID := stableID("dependency:pulse-authentik")
if _, err := tx.Exec(ctx, `INSERT INTO service_dependencies
(id,service_id,depends_on_service_id,relation_type,confidence,confirmed,first_seen_at,last_seen_at)
VALUES ($1,$2,$3,'depends_on',1,true,now(),now())
ON CONFLICT (service_id,depends_on_service_id,relation_type) WHERE source_id IS NULL
DO UPDATE SET confidence=1,confirmed=true,last_seen_at=now(),archived_at=NULL`,
dependencyID, seeds[0].id, seeds[1].id); err != nil {
return Summary{}, fmt.Errorf("upsert Pulse authentication dependency: %w", err)
}
summary.Dependencies = 1
}
if err := tx.Commit(ctx); err != nil {
return Summary{}, fmt.Errorf("commit service defaults: %w", err)
}
return summary, nil
}
func desired(ctx context.Context, options Options, policy probe.NetworkPolicy, resolver probe.Resolver) ([]serviceSeed, error) {
publicURL := strings.TrimSpace(options.PublicURL)
issuerURL := strings.TrimSpace(options.OIDCIssuer)
if publicURL == "" && issuerURL == "" {
return nil, nil
}
if publicURL == "" || issuerURL == "" {
return nil, errors.New("PULSE_PUBLIC_URL and PULSE_OIDC_ISSUER must both be configured for system service monitoring")
}
public, err := validateHTTPS(ctx, policy, resolver, publicURL)
if err != nil {
return nil, fmt.Errorf("validate PULSE_PUBLIC_URL for service monitoring: %w", err)
}
issuer, err := validateHTTPS(ctx, policy, resolver, issuerURL)
if err != nil {
return nil, fmt.Errorf("validate PULSE_OIDC_ISSUER for service monitoring: %w", err)
}
publicPort := urlPort(public)
issuerPort := urlPort(issuer)
healthTarget := probe.Target{Scheme: "https", Host: public.Hostname(), Port: publicPort, Path: joinURLPath(public.Path, "healthz")}
issuerTarget := probe.Target{Scheme: "https", Host: issuer.Hostname(), Port: issuerPort, Path: joinURLPath(issuer.Path, ".well-known/openid-configuration")}
tlsTarget := probe.Target{Scheme: "tls", Host: public.Hostname(), Port: publicPort}
return []serviceSeed{
{id: stableID("service:pulse"), name: "ITWorx Pulse", description: "Publieke Pulse-applicatie en API", endpointID: stableID("endpoint:pulse-public"), endpointName: "Publieke HTTPS-endpoint", endpointType: "http", target: healthTarget,
probes: []probeSeed{{id: stableID("probe:pulse-health"), name: "Pulse health", kind: probe.TypeHTTP, target: healthTarget, interval: 30, timeout: 10, expected: []int{200}, verifyTLS: true}, {id: stableID("probe:pulse-tls"), name: "Pulse TLS-certificaat", kind: probe.TypeTLS, target: tlsTarget, interval: 21600, timeout: 10, verifyTLS: true}}},
{id: stableID("service:authentik"), name: "Authentik SSO", description: "OIDC-identiteitsprovider voor Pulse", endpointID: stableID("endpoint:authentik-discovery"), endpointName: "OIDC discovery-endpoint", endpointType: "http", target: issuerTarget,
probes: []probeSeed{{id: stableID("probe:authentik-discovery"), name: "Authentik OIDC discovery", kind: probe.TypeHTTP, target: issuerTarget, interval: 60, timeout: 10, expected: []int{200}, verifyTLS: true}}},
}, nil
}
func validateHTTPS(ctx context.Context, policy probe.NetworkPolicy, resolver probe.Resolver, raw string) (*url.URL, error) {
parsed, err := policy.ValidateURL(ctx, resolver, raw)
if err != nil {
return nil, err
}
if parsed.Scheme != "https" || parsed.RawQuery != "" || parsed.User != nil || parsed.Fragment != "" {
return nil, errors.New("system service URL must be HTTPS without credentials, query parameters, or fragment")
}
return parsed, nil
}
func joinURLPath(base, suffix string) string {
joined := path.Join("/", base, suffix)
if !strings.HasPrefix(joined, "/") {
return "/" + joined
}
return joined
}
func urlPort(value *url.URL) int {
if value.Port() == "" {
return 443
}
var port int
_, _ = fmt.Sscanf(value.Port(), "%d", &port)
return port
}
func stableID(key string) string {
return reconciliation.StableEntityID(identityNamespace, "service-default", key)
}
@@ -0,0 +1,64 @@
package servicedefaults
import (
"context"
"net/netip"
"os"
"testing"
"time"
"github.com/itworx/pulse/internal/database"
"github.com/itworx/pulse/internal/probe"
"github.com/jackc/pgx/v5/pgxpool"
)
func TestSeedPostgreSQLIsAtomicAndIdempotent(t *testing.T) {
dsn := os.Getenv("PULSE_TEST_DATABASE_URL")
if dsn == "" {
t.Skip("PULSE_TEST_DATABASE_URL is not set")
}
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
defer cancel()
pool, err := database.NewPool(ctx, database.Config{URL: dsn, MaxConns: 4, MinConns: 1})
if err != nil {
t.Fatal(err)
}
defer pool.Close()
if err := database.Migrate(ctx, pool); err != nil {
t.Fatal(err)
}
resolve := resolver{"pulse.example": {netip.MustParseAddr("203.0.113.10")}, "auth.example": {netip.MustParseAddr("198.51.100.20")}}
options := Options{PublicURL: "https://pulse.example", OIDCIssuer: "https://auth.example/application/o/pulse/"}
for run := 0; run < 2; run++ {
summary, err := Seed(ctx, pool, options, probe.NetworkPolicy{}, resolve)
if err != nil {
t.Fatal(err)
}
if summary != (Summary{Services: 2, Endpoints: 2, Probes: 3, Dependencies: 1}) {
t.Fatalf("unexpected summary: %#v", summary)
}
}
assertCount(t, ctx, pool, `SELECT count(*) FROM services WHERE labels->>'managedBy'='pulse-system-defaults'`, 2)
assertCount(t, ctx, pool, `SELECT count(*) FROM probes WHERE service_id IN ($1,$2) AND archived_at IS NULL`, 3, stableID("service:pulse"), stableID("service:authentik"))
assertCount(t, ctx, pool, `SELECT count(*) FROM service_dependencies WHERE service_id=$1 AND depends_on_service_id=$2 AND confirmed=true`, 1, stableID("service:pulse"), stableID("service:authentik"))
assertCount(t, ctx, pool, `SELECT count(*) FROM services WHERE id IN ($1,$2) AND revision=1`, 2, stableID("service:pulse"), stableID("service:authentik"))
assertCount(t, ctx, pool, `SELECT count(*) FROM probes WHERE service_id IN ($1,$2) AND revision=1`, 3, stableID("service:pulse"), stableID("service:authentik"))
// Invalid replacement configuration fails before the transaction and leaves
// the accepted baseline unchanged.
if _, err := Seed(ctx, pool, Options{PublicURL: "https://10.0.0.2", OIDCIssuer: options.OIDCIssuer}, probe.NetworkPolicy{}, resolve); err == nil {
t.Fatal("expected blocked private replacement")
}
assertCount(t, ctx, pool, `SELECT count(*) FROM probes WHERE service_id IN ($1,$2) AND archived_at IS NULL`, 3, stableID("service:pulse"), stableID("service:authentik"))
}
func assertCount(t *testing.T, ctx context.Context, pool *pgxpool.Pool, query string, expected int, args ...any) {
t.Helper()
var count int
if err := pool.QueryRow(ctx, query, args...).Scan(&count); err != nil {
t.Fatal(err)
}
if count != expected {
t.Fatalf("count=%d, want %d for %s", count, expected, query)
}
}
+54
View File
@@ -0,0 +1,54 @@
package servicedefaults
import (
"context"
"net/netip"
"testing"
"github.com/itworx/pulse/internal/probe"
)
type resolver map[string][]netip.Addr
func (r resolver) LookupIP(_ context.Context, host string) ([]netip.Addr, error) { return r[host], nil }
func TestDesiredBuildsBoundedPublicServiceGraph(t *testing.T) {
addresses := resolver{"pulse.example": {netip.MustParseAddr("203.0.113.10")}, "auth.example": {netip.MustParseAddr("198.51.100.20")}}
seeds, err := desired(context.Background(), Options{PublicURL: "https://pulse.example", OIDCIssuer: "https://auth.example/application/o/pulse/"}, probe.NetworkPolicy{}, addresses)
if err != nil {
t.Fatal(err)
}
if len(seeds) != 2 || len(seeds[0].probes) != 2 || len(seeds[1].probes) != 1 {
t.Fatalf("unexpected defaults: %#v", seeds)
}
if seeds[0].probes[0].target.Path != "/healthz" || seeds[1].probes[0].target.Path != "/application/o/pulse/.well-known/openid-configuration" {
t.Fatalf("unexpected targets: %#v %#v", seeds[0].probes[0].target, seeds[1].probes[0].target)
}
if seeds[0].id == seeds[1].id || seeds[0].id != stableID("service:pulse") {
t.Fatal("service identities are not deterministic and distinct")
}
}
func TestDesiredRejectsUnsafeOrPartialConfiguration(t *testing.T) {
public := resolver{"pulse.example": {netip.MustParseAddr("203.0.113.10")}, "private.example": {netip.MustParseAddr("10.0.0.10")}}
tests := []Options{
{PublicURL: "https://pulse.example"},
{PublicURL: "http://pulse.example", OIDCIssuer: "https://pulse.example"},
{PublicURL: "https://user:secret@pulse.example", OIDCIssuer: "https://pulse.example"},
{PublicURL: "https://private.example", OIDCIssuer: "https://pulse.example"},
{PublicURL: "https://169.254.169.254", OIDCIssuer: "https://pulse.example"},
}
for _, options := range tests {
if _, err := desired(context.Background(), options, probe.NetworkPolicy{}, public); err == nil {
t.Fatalf("unsafe configuration was accepted: %#v", options)
}
}
}
func TestDesiredAllowsExplicitPrivateNetworkOnly(t *testing.T) {
private := resolver{"pulse.internal": {netip.MustParseAddr("10.0.0.10")}, "auth.internal": {netip.MustParseAddr("10.0.0.11")}}
policy := probe.NetworkPolicy{AllowedNetworks: []netip.Prefix{netip.MustParsePrefix("10.0.0.0/24")}}
if _, err := desired(context.Background(), Options{PublicURL: "https://pulse.internal", OIDCIssuer: "https://auth.internal"}, policy, private); err != nil {
t.Fatal(err)
}
}