workflow: svcauth, tenantregistryclient aus common v0.1.0
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) Canceled after 0s
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (pull_request) Canceled after 0s
CI / Web (shl) (pull_request) Failing after 11s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Failing after 23s
CI / Core-Modul (Build/Vet/Test) (push) Failing after 1m6s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Successful in 3s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (push) Successful in 4s
CI / Web (dms-browser) (push) Failing after 1m31s
CI / Web (pdf-viewer) (push) Failing after 1m3s
CI / Web (shl) (push) Failing after 14s
Supply-Chain-Scan (Go) / govulncheck (push) Failing after 4m11s
Workflow-Schnittstellen-Vertragstests / contract-tests (push) Failing after 41s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (pull_request) Successful in 7s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (pull_request) Successful in 8s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (pull_request) Failing after 30s
CI / Web (dms-browser) (pull_request) Failing after 1m24s
CI / Web (pdf-viewer) (pull_request) Failing after 57s
CI / Core-Modul (Build/Vet/Test) (pull_request) Failing after 11m29s
Supply-Chain-Scan (Go) / govulncheck (pull_request) Failing after 3m26s
Supply-Chain-Scan (npm) / npm-audit (pull_request) Failing after 1m57s
Workflow-Schnittstellen-Vertragstests / contract-tests (pull_request) Failing after 57s
Workflow-Pflichttest-Gate / pflichttest-gate (pull_request) Failing after 1m13s
Core-Schnittstellen-Vertragstests / contract-tests (pull_request) Successful in 10m30s
Core-Pflichttest-Gate / pflichttest-gate (pull_request) Successful in 10m25s
RBAC-Rollenhierarchie-Pflichtgate / rbac-policy-invariant (pull_request) Successful in 9m47s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Failing after 3s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (pull_request) Failing after 3s
DB-Integrationstests / db-tests (pull_request) Canceled after 0s

Das Pflichttest-Gate von workflow verweist nicht mehr auf die geloeschten
Pakete (common hat ein eigenes Gate).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
patrickandClaude Sonnet 5.5 committed 2026-10-27 23:33:55 +01:00
1 parent 184a219c8a
commit eaffcaf885
15 files changed
+36 -102

No files matched your search

+1 -1
View File
@@ -16,6 +16,7 @@ import (
"github.com/jackc/pgx/v5/pgxpool"
"gitea.perlbach24.de/scripte/nexarch/common/tenantregistryclient"
"gitea.perlbach24.de/scripte/nexarch/workflow/internal/approval"
"gitea.perlbach24.de/scripte/nexarch/workflow/internal/approvalapi"
"gitea.perlbach24.de/scripte/nexarch/workflow/internal/backchannel"
@@ -33,7 +34,6 @@ import (
"gitea.perlbach24.de/scripte/nexarch/workflow/internal/routingruleapi"
"gitea.perlbach24.de/scripte/nexarch/workflow/internal/routingsuggestclient"
"gitea.perlbach24.de/scripte/nexarch/workflow/internal/task"
"gitea.perlbach24.de/scripte/nexarch/workflow/internal/tenantregistryclient"
)
func requireEnv(name string) string {
+4 -1
View File
@@ -2,7 +2,10 @@ module gitea.perlbach24.de/scripte/nexarch/workflow
go 1.25.0
require github.com/jackc/pgx/v5 v5.9.2
require (
gitea.perlbach24.de/scripte/nexarch/common v0.1.0
github.com/jackc/pgx/v5 v5.9.2
)
require (
github.com/jackc/pgpassfile v1.0.0 // indirect
+2
View File
@@ -1,3 +1,5 @@
gitea.perlbach24.de/scripte/nexarch/common v0.1.0 h1:biNzFr2LOMZC7b1leY3smQtrMmSMp6IW80OvR4LSjLY=
gitea.perlbach24.de/scripte/nexarch/common v0.1.0/go.mod h1:CiEImG++QMt1xZqSMeDJhPiB7sfWTLZOwjS6OY/Iguc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -302,4 +302,3 @@ func TestForObject_RegistryTransportError_FailsClosed(t *testing.T) {
t.Fatalf("erwartet ErrForbidden bei registry-transportfehler (fail-closed), bekommen %v", err)
}
}
@@ -35,10 +35,10 @@ type Detail struct {
type KanbanColumn string
const (
ColumnOpen KanbanColumn = "open"
ColumnThisWeek KanbanColumn = "this_week"
ColumnOverdue KanbanColumn = "overdue"
ColumnDone KanbanColumn = "done"
ColumnOpen KanbanColumn = "open"
ColumnThisWeek KanbanColumn = "this_week"
ColumnOverdue KanbanColumn = "overdue"
ColumnDone KanbanColumn = "done"
)
// KanbanItem ist eine Wiedervorlage mitsamt der Spalte, in der sie gerade
@@ -5,8 +5,8 @@ import (
"net/http"
"net/http/httptest"
"os"
"strings"
"path/filepath"
"strings"
"testing"
"time"
@@ -174,13 +174,13 @@ func (d *Dispatcher) Dispatch(ctx context.Context) (int, error) {
// dasselbe Ereignis reserviert nicht erneut und legt daher auch
// keine zweite Aufgabe an (Akzeptanzkriterium 2).
// 2. Aufgabe/Genehmigung wird angelegt.
// 3a. Erfolg: die Reservierung wird mit der erzeugten Objekt-ID
// bestaetigt und module_events als verarbeitet markiert.
// 3b. Fehlschlag: die Reservierung wird wieder geloescht, damit ein
// spaeterer Dispatch-Lauf es erneut versuchen kann -- das
// verbleibende Restrisiko ist ein Absturz exakt zwischen 2 und 3a,
// das Ereignis bliebe dann dauerhaft reserviert ohne erzeugtes
// Objekt (dokumentiert in ENG-09-PRUEFPROTOKOLL.md).
// 3a. Erfolg: die Reservierung wird mit der erzeugten Objekt-ID
// bestaetigt und module_events als verarbeitet markiert.
// 3b. Fehlschlag: die Reservierung wird wieder geloescht, damit ein
// spaeterer Dispatch-Lauf es erneut versuchen kann -- das
// verbleibende Restrisiko ist ein Absturz exakt zwischen 2 und 3a,
// das Ereignis bliebe dann dauerhaft reserviert ohne erzeugtes
// Objekt (dokumentiert in ENG-09-PRUEFPROTOKOLL.md).
func (d *Dispatcher) dispatchOne(ctx context.Context, e pendingEvent) (bool, error) {
rule, ok, err := d.rules.ruleFor(ctx, d.pool, e.ModuleName, e.ObjectType, e.Trigger)
if err != nil {
+1 -1
View File
@@ -10,7 +10,7 @@ import (
"github.com/jackc/pgx/v5/pgxpool"
"gitea.perlbach24.de/scripte/nexarch/workflow/internal/svcauth"
"gitea.perlbach24.de/scripte/nexarch/common/svcauth"
)
// TenantVerifier prueft einen vom aufrufenden Modul mitgelieferten
@@ -17,9 +17,7 @@ import (
// sensitivePathPatterns beschreibt die Bereiche aus
// workflow/docs/TESTSTRATEGIE.md Abschnitt 4.
var sensitivePathPatterns = []*regexp.Regexp{
regexp.MustCompile(`(^|/)workflow/internal/svcauth/`),
regexp.MustCompile(`(^|/)workflow/internal/moduleadapter/`),
regexp.MustCompile(`(^|/)workflow/internal/tenantregistryclient/`),
regexp.MustCompile(`(^|/)workflow/internal/backchannel/`),
regexp.MustCompile(`(^|/)workflow/internal/backchannelapi/`),
regexp.MustCompile(`(^|/)workflow/internal/dualcheck/`),
@@ -1,24 +1,24 @@
// Negativtest des Gates selbst (QA-01 Pruefung 1): ein Diff mit
// geaenderter workflow/internal/svcauth/svcauth.go ohne begleitende
// geaenderter workflow/internal/moduleadapter/moduleadapter.go ohne begleitende
// Testdatei muss als Verstoss erkannt werden.
package pflichttestgate
import "testing"
func TestCheckDiff_FlagsSensitiveChangeWithoutTest(t *testing.T) {
violations := CheckDiff([]string{"workflow/internal/svcauth/svcauth.go"})
violations := CheckDiff([]string{"workflow/internal/moduleadapter/moduleadapter.go"})
if len(violations) != 1 {
t.Fatalf("erwartet genau 1 verstoss, habe %d: %+v", len(violations), violations)
}
if violations[0].Package != "workflow/internal/svcauth" {
if violations[0].Package != "workflow/internal/moduleadapter" {
t.Fatalf("falsches package gemeldet: %+v", violations[0])
}
}
func TestCheckDiff_PassesWhenTestFileAccompanies(t *testing.T) {
violations := CheckDiff([]string{
"workflow/internal/svcauth/svcauth.go",
"workflow/internal/svcauth/svcauth_test.go",
"workflow/internal/moduleadapter/moduleadapter.go",
"workflow/internal/moduleadapter/moduleadapter_test.go",
})
if len(violations) != 0 {
t.Fatalf("erwartet keine verstoesse, habe: %+v", violations)
@@ -34,9 +34,7 @@ func TestCheckDiff_IgnoresNonSensitivePaths(t *testing.T) {
func TestCheckDiff_CoversAllSensitivePackages(t *testing.T) {
files := []string{
"workflow/internal/svcauth/x.go",
"workflow/internal/moduleadapter/x.go",
"workflow/internal/tenantregistryclient/x.go",
"workflow/internal/backchannel/x.go",
"workflow/internal/backchannelapi/x.go",
"workflow/internal/dualcheck/x.go",
@@ -19,12 +19,12 @@ import (
// Decision ist das Ergebnis einer Ausfuehrung: entweder eine passende Regel
// mit ihrer Aktion, oder keine Regel (Klaerungskorb).
type Decision struct {
Matched bool
RuleID string
RuleName string
Action routingrule.Action
InBasket bool
BasketID string
Matched bool
RuleID string
RuleName string
Action routingrule.Action
InBasket bool
BasketID string
}
type Engine struct {
+2 -2
View File
@@ -64,8 +64,8 @@ func (s *Server) handleList(w http.ResponseWriter, r *http.Request, _ string) {
}
type ruleInput struct {
Name string `json:"name"`
Priority int `json:"priority"`
Name string `json:"name"`
Priority int `json:"priority"`
Conditions []routingrule.Condition `json:"conditions"`
Actions []routingrule.Action `json:"actions"`
}
+3 -3
View File
@@ -13,9 +13,9 @@ import (
// TestCase ist ein Objekt aus dem Testkorpus, optional mit einer erwarteten
// Regel-ID (leer = "keine Regel soll greifen").
type TestCase struct {
Label string
Object map[string]any
ExpectedRuleID string
Label string
Object map[string]any
ExpectedRuleID string
}
// Result ist das Simulationsergebnis fuer einen TestCase: tatsaechliche
-19
View File
@@ -1,19 +0,0 @@
// Package svcauth vergleicht Service-Token in konstanter Zeit (Muster aus
// archive/internal/svcauth, Lehre aus RET-14/F-08: ohne diesen Schutz
// beim ersten Entwurf des Adapters einbauen statt nachzuruesten).
package svcauth
import (
"crypto/sha256"
"crypto/subtle"
)
// Equal vergleicht die SHA-256-Werte beider Eingaben in konstanter Zeit.
// Ein leeres erwartetes Token stimmt nie.
func Equal(got, want string) bool {
if want == "" {
return false
}
g, w := sha256.Sum256([]byte(got)), sha256.Sum256([]byte(want))
return subtle.ConstantTimeCompare(g[:], w[:]) == 1
}
@@ -1,47 +0,0 @@
// Package tenantregistryclient ist ein schlanker HTTP-Client fuer Core TEN-01
// (Tenant-Registry); Workflow ist ein eigenes Go-Modul und kann Cores Pakete
// nicht importieren. Gleiches Muster wie dms/internal/tenantregistryclient
// und archive/internal/tenantregistryclient.
package tenantregistryclient
import (
"context"
"fmt"
"net/http"
"net/url"
"time"
)
type Client struct {
BaseURL string
ServiceToken string
HTTPClient *http.Client
}
func New(baseURL, serviceToken string) *Client {
return &Client{BaseURL: baseURL, ServiceToken: serviceToken, HTTPClient: &http.Client{Timeout: 10 * time.Second}}
}
// VerifyTenant fragt Core, ob tenantSlug als Tenant gefuehrt wird. Transport-
// und Serverfehler kommen als Fehler zurueck, nie als "gueltig": der Aufrufer
// muss fail-closed reagieren.
func (c *Client) VerifyTenant(ctx context.Context, tenantSlug string) (bool, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.BaseURL+"/tenants/"+url.PathEscape(tenantSlug), nil)
if err != nil {
return false, fmt.Errorf("tenantregistryclient: request bauen: %w", err)
}
req.Header.Set("X-Service-Token", c.ServiceToken)
resp, err := c.HTTPClient.Do(req)
if err != nil {
return false, fmt.Errorf("tenantregistryclient: aufruf fehlgeschlagen: %w", err)
}
defer func() { _ = resp.Body.Close() }()
switch resp.StatusCode {
case http.StatusOK:
return true, nil
case http.StatusNotFound:
return false, nil
default:
return false, fmt.Errorf("tenantregistryclient: unerwarteter status %d", resp.StatusCode)
}
}