Compare commits

...
Author SHA1 Message Date
patrickandClaude Sonnet 5 35904c0a35 test: fakeKEKProvider/fakeKEK-Dopplung in testutil-Pakete konsolidiert
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) Canceled after 0s
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (pull_request) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (pull_request) Canceled after 0s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (pull_request) Canceled after 0s
Archive-Pflichttest-Gate / pflichttest-gate (pull_request) Canceled after 0s
Supply-Chain-Scan (Go) / govulncheck (push) Canceled after 0s
Supply-Chain-Scan (Go) / govulncheck (pull_request) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
CI / Core-Modul (Build/Vet/Test) (pull_request) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (pull_request) Canceled after 0s
CI / Web (dms-browser) (pull_request) Canceled after 0s
CI / Web (pdf-viewer) (pull_request) Canceled after 0s
CI / Web (shl) (pull_request) Canceled after 0s
Connect-Schnittstellen-Vertragstests / contract-tests (push) Canceled after 0s
Connect-Schnittstellen-Vertragstests / contract-tests (pull_request) Canceled after 0s
Core-Schnittstellen-Vertragstests / contract-tests (pull_request) Canceled after 0s
Supply-Chain-Scan (npm) / npm-audit (pull_request) Canceled after 0s
Core-Pflichttest-Gate / pflichttest-gate (pull_request) Canceled after 0s
RBAC-Rollenhierarchie-Pflichtgate / rbac-policy-invariant (pull_request) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (pull_request) Canceled after 0s
Fable-Review auf Code-Dopplung (P1). Byteidentische Test-Doubles, die
unabhaengig in vielen *_test.go-Dateien dupliziert waren, je Modul in
ein neues internal/testutil-Paket gezogen (Go-Modulgrenzen verhindern
ein gemeinsames Paket ueber dms/archive/connect hinweg):

- dms/internal/testutil.FakeKEKProvider: 14 Dateien (thumbnail,
  versioningapi, documentapi, pdfsign, docmerge, pdfconvert, export,
  watchfolder, downloadapi, malwarescan, uploadapi, versioning,
  migrationdocument, upload) + 2 weitere Nutzstellen ohne eigene
  Typdefinition (versioning/diff_test.go, uploadapi/int19_...).
  dms/internal/crypto/service_test.go NICHT angefasst -- eigene
  Call-Counting-Variante, keine echte Dopplung.
- archive/internal/testutil.FakeKEKProvider: backup + objectbackup
  (tenant-keyed Map-Variante, von der dms-Variante verschieden).
- connect/internal/testutil.FakeKEK: 7 Dateien (backupconnector,
  credential, contracttest, connectorsetupapi, webhooksub x2,
  m365connector). connect/internal/crypto/envelope_test.go NICHT
  angefasst -- einziges Vorkommen, keine Dopplung.

fakeUsageReporter/fakeVerifier bewusst NICHT konsolidiert: bei Pruefung
stellten sich die meisten Vorkommen als inhaltlich verschiedene
Varianten heraus (unterschiedliche Felder/Fehlerpfade), keine echte
Kopie. Die eine echte Dopplung (archive/workflow moduleadapter) liegt
ueber einer Modulgrenze, nicht ohne neue Shared-Library loesbar.

go build/vet/test (-p 1) sauber in allen betroffenen Paketen von dms,
archive, connect auf Testhost 131.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-19 14:48:02 +02:00
28 changed files with 119 additions and 195 deletions

No files matched your search

+4 -20
View File
@@ -3,32 +3,16 @@ package backup
import (
"bytes"
"context"
"errors"
"os"
"path/filepath"
"testing"
"time"
"gitea.perlbach24.de/scripte/nexarch/archive/internal/testutil"
)
// fakeKEKProvider liefert deterministische, tenant-spezifische KEKs für
// Tests, ohne einen echten Core-API-10-Aufruf zu brauchen.
type fakeKEKProvider struct {
keks map[string][]byte
}
func newFakeKEKProvider() *fakeKEKProvider {
return &fakeKEKProvider{keks: map[string][]byte{
"mandant-a": bytes.Repeat([]byte{0xAA}, 32),
"mandant-b": bytes.Repeat([]byte{0xBB}, 32),
}}
}
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
kek, ok := f.keks[tenantSlug]
if !ok {
return nil, errors.New("fakeKEKProvider: unbekannter mandant")
}
return kek, nil
func newFakeKEKProvider() *testutil.FakeKEKProvider {
return testutil.NewFakeKEKProvider()
}
// TestEncryptGeneration_RemovesPlaintextReadability ist Prüfung 1 (BAK-09):
@@ -2,37 +2,15 @@ package objectbackup
import (
"context"
"errors"
"os"
"path/filepath"
"testing"
"gitea.perlbach24.de/scripte/nexarch/archive/internal/testutil"
)
type fakeKEKProvider struct {
keks map[string][]byte
}
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
kek, ok := f.keks[tenantSlug]
if !ok {
return nil, errors.New("fakeKEKProvider: unbekannter mandant")
}
return kek, nil
}
func newFakeKEKProvider() *fakeKEKProvider {
return &fakeKEKProvider{keks: map[string][]byte{
"mandant-a": bytesOf(0xAA),
"mandant-b": bytesOf(0xBB),
}}
}
func bytesOf(b byte) []byte {
out := make([]byte, 32)
for i := range out {
out[i] = b
}
return out
func newFakeKEKProvider() *testutil.FakeKEKProvider {
return testutil.NewFakeKEKProvider()
}
// TestTenantEncryptedConfig_BackupAndRestore ist Pruefung 2 (BAK-09):
+32
View File
@@ -0,0 +1,32 @@
// Package testutil buendelt Test-Doubles, die identisch in mehreren
// archive/internal-Paketen dupliziert waren (Fable-Review auf Code-Dopplung).
package testutil
import (
"bytes"
"context"
"errors"
)
// FakeKEKProvider liefert deterministische, tenant-spezifische KEKs fuer
// Tests, ohne einen echten Core-API-10-Aufruf zu brauchen.
type FakeKEKProvider struct {
Keks map[string][]byte
}
// NewFakeKEKProvider liefert einen FakeKEKProvider mit den beiden in
// Tests ueblichen Mandanten "mandant-a"/"mandant-b" vorbefuellt.
func NewFakeKEKProvider() *FakeKEKProvider {
return &FakeKEKProvider{Keks: map[string][]byte{
"mandant-a": bytes.Repeat([]byte{0xAA}, 32),
"mandant-b": bytes.Repeat([]byte{0xBB}, 32),
}}
}
func (f *FakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
kek, ok := f.Keks[tenantSlug]
if !ok {
return nil, errors.New("fakeKEKProvider: unbekannter mandant")
}
return kek, nil
}
@@ -20,18 +20,15 @@ import (
"gitea.perlbach24.de/scripte/nexarch/connect/internal/registry"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/syncjob"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testutil"
)
type fakeKEK struct{ key []byte }
func (f *fakeKEK) TenantKEK(_ context.Context, _ string) ([]byte, error) { return f.key, nil }
func newTestKEK() *fakeKEK {
func newTestKEK() *testutil.FakeKEK {
key := make([]byte, crypto.KEKSize)
for i := range key {
key[i] = byte(i + 7)
}
return &fakeKEK{key: key}
return &testutil.FakeKEK{KEK: key}
}
// mockS3 is a minimal S3-compatible test double: it requires a well-formed
@@ -170,7 +167,7 @@ func TestClient_ExportIsEncryptedInTransit(t *testing.T) {
t.Fatalf("decrypted = %q, want %q", opened, plaintext)
}
wrongKEK := &fakeKEK{key: make([]byte, crypto.KEKSize)}
wrongKEK := &testutil.FakeKEK{KEK: make([]byte, crypto.KEKSize)}
wrongSvc := crypto.NewService(wrongKEK)
if _, err := wrongSvc.Open(context.Background(), "acme", &crypto.Sealed{
Ciphertext: env.Ciphertext, WrappedDEK: env.WrappedDEK,
@@ -18,14 +18,9 @@ import (
"gitea.perlbach24.de/scripte/nexarch/connect/internal/fieldmapping"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/migrate"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testutil"
)
type fakeKEK struct{ kek []byte }
func (f *fakeKEK) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
func newTestServer(t *testing.T) *http.ServeMux {
t.Helper()
dsn := os.Getenv("TEST_TENANT_DSN")
@@ -44,7 +39,7 @@ func newTestServer(t *testing.T) *http.ServeMux {
if _, err := migrate.Up(context.Background(), pool, migrations); err != nil {
t.Fatalf("migrationen anwenden: %v", err)
}
cryptoSvc := connectcrypto.NewService(&fakeKEK{kek: bytes.Repeat([]byte{0x11}, connectcrypto.KEKSize)})
cryptoSvc := connectcrypto.NewService(&testutil.FakeKEK{KEK: bytes.Repeat([]byte{0x11}, connectcrypto.KEKSize)})
s := NewServer(credential.NewStore(pool, cryptoSvc), fieldmapping.NewStore(pool))
mux := http.NewServeMux()
s.RegisterRoutes(mux)
@@ -16,6 +16,7 @@ import (
connectcrypto "gitea.perlbach24.de/scripte/nexarch/connect/internal/crypto"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/migrate"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testutil"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/webhookclient"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/webhooksub"
)
@@ -165,9 +166,6 @@ func TestContract_DeliverySignatureHeader_MatchesDocumentedName(t *testing.T) {
}
}
type fakeKEK struct{ kek []byte }
func (f *fakeKEK) TenantKEK(context.Context, string) ([]byte, error) { return f.kek, nil }
// fakeCoreWebhookAPI reicht fuer Vertrag 4 aus, um ein echtes, von Connect
// generiertes Geheimnis an Core "weiterzugeben" -- dasselbe, ausdruecklich
@@ -221,7 +219,7 @@ func setupDeliveryContractTest(t *testing.T) deliveryContractEnv {
fakeCore, coreSecret := newFakeCoreForDeliveryContract()
t.Cleanup(fakeCore.Close)
cryptoSvc := connectcrypto.NewService(&fakeKEK{kek: make([]byte, connectcrypto.KEKSize)})
cryptoSvc := connectcrypto.NewService(&testutil.FakeKEK{KEK: make([]byte, connectcrypto.KEKSize)})
mgr := webhooksub.NewManager(pool, cryptoSvc, webhookclient.New(fakeCore.URL, "svc-token-test"), "https://connect.example.test/connector-webhooks/deliveries")
return deliveryContractEnv{Manager: mgr, FakeCore: fakeCore, coreSecret: coreSecret}
}
@@ -19,14 +19,9 @@ import (
connectcrypto "gitea.perlbach24.de/scripte/nexarch/connect/internal/crypto"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/migrate"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testutil"
)
type fakeKEK struct{ kek []byte }
func (f *fakeKEK) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
func setup(t *testing.T) (*credential.Store, *pgxpool.Pool) {
t.Helper()
dsn := os.Getenv("TEST_TENANT_DSN")
@@ -44,7 +39,7 @@ func setup(t *testing.T) (*credential.Store, *pgxpool.Pool) {
t.Fatalf("migrationen anwenden: %v", err)
}
cryptoSvc := connectcrypto.NewService(&fakeKEK{kek: bytes.Repeat([]byte{0x11}, connectcrypto.KEKSize)})
cryptoSvc := connectcrypto.NewService(&testutil.FakeKEK{KEK: bytes.Repeat([]byte{0x11}, connectcrypto.KEKSize)})
store := credential.NewStore(pool, cryptoSvc)
return store, pool
}
@@ -119,7 +114,7 @@ func TestStore_WrongKeyFailsClosed(t *testing.T) {
t.Fatalf("put: %v", err)
}
wrongKEK := connectcrypto.NewService(&fakeKEK{kek: bytes.Repeat([]byte{0x22}, connectcrypto.KEKSize)})
wrongKEK := connectcrypto.NewService(&testutil.FakeKEK{KEK: bytes.Repeat([]byte{0x22}, connectcrypto.KEKSize)})
wrongStore := credential.NewStore(pool, wrongKEK)
if _, _, _, err := wrongStore.Get(ctx, ref); !errors.Is(err, connectcrypto.ErrDecryptFailed) {
t.Fatalf("erwartet ErrDecryptFailed, habe %v", err)
@@ -16,14 +16,9 @@ import (
"gitea.perlbach24.de/scripte/nexarch/connect/internal/migrate"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testcorpus"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testutil"
)
type fakeKEK struct{ kek []byte }
func (f *fakeKEK) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
func setupCredentialStore(t *testing.T) *credential.Store {
t.Helper()
dsn := os.Getenv("TEST_TENANT_DSN")
@@ -41,7 +36,7 @@ func setupCredentialStore(t *testing.T) *credential.Store {
t.Fatalf("migrationen anwenden: %v", err)
}
cryptoSvc := connectcrypto.NewService(&fakeKEK{kek: make([]byte, connectcrypto.KEKSize)})
cryptoSvc := connectcrypto.NewService(&testutil.FakeKEK{KEK: make([]byte, connectcrypto.KEKSize)})
return credential.NewStore(pool, cryptoSvc)
}
+13
View File
@@ -0,0 +1,13 @@
// Package testutil buendelt Test-Doubles, die identisch in mehreren
// connect/internal-Paketen dupliziert waren (Fable-Review auf Code-Dopplung).
package testutil
import "context"
// FakeKEK ist ein Test-Double fuer das KEKProvider-Interface -- liefert
// immer denselben festen Schluessel, unabhaengig vom Tenant.
type FakeKEK struct{ KEK []byte }
func (f *FakeKEK) TenantKEK(_ context.Context, _ string) ([]byte, error) {
return f.KEK, nil
}
+2 -7
View File
@@ -19,14 +19,9 @@ import (
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/webhookclient"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/webhooksub"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testutil"
)
type fakeKEK struct{ kek []byte }
func (f *fakeKEK) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
// fakeCoreWebhookAPI reproduziert Core API-07s Subscribe/Unsubscribe-Vertrag
// -- der von dieser Kachel ausdruecklich erlaubte "minimal gestubte
// Core-Webhook-Registry-Endpunkt" fuer den echten End-zu-Ende-Test (echte
@@ -131,7 +126,7 @@ func setup(t *testing.T) testEnv {
coreSrv := httptest.NewServer(http.HandlerFunc(core.handle))
t.Cleanup(coreSrv.Close)
cryptoSvc := connectcrypto.NewService(&fakeKEK{kek: make([]byte, connectcrypto.KEKSize)})
cryptoSvc := connectcrypto.NewService(&testutil.FakeKEK{KEK: make([]byte, connectcrypto.KEKSize)})
client := webhookclient.New(coreSrv.URL, "svc-token-test")
mgr := webhooksub.NewManager(pool, cryptoSvc, client, "https://connect.example.test/connector-webhooks/deliveries")
@@ -8,6 +8,7 @@ import (
"testing"
connectcrypto "gitea.perlbach24.de/scripte/nexarch/connect/internal/crypto"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/testutil"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/webhookclient"
"gitea.perlbach24.de/scripte/nexarch/connect/internal/webhooksub"
)
@@ -61,7 +62,7 @@ func TestSubscribe_CoreFailure_PersistsNothingLocally(t *testing.T) {
}))
defer failingCore.Close()
cryptoSvc := connectcrypto.NewService(&fakeKEK{kek: make([]byte, connectcrypto.KEKSize)})
cryptoSvc := connectcrypto.NewService(&testutil.FakeKEK{KEK: make([]byte, connectcrypto.KEKSize)})
mgr := webhooksub.NewManager(env.Pool, cryptoSvc, webhookclient.New(failingCore.URL, "svc-token-test"), "https://connect.example.test/connector-webhooks/deliveries")
mgr.RegisterAction("testcrm", "dms.document.archived", func(context.Context, []byte) error { return nil })
@@ -138,7 +139,7 @@ func TestUnsubscribe_CoreFailure_KeepsLocalRowForRetry(t *testing.T) {
w.WriteHeader(http.StatusInternalServerError)
}))
defer brokenCore.Close()
cryptoSvc := connectcrypto.NewService(&fakeKEK{kek: make([]byte, connectcrypto.KEKSize)})
cryptoSvc := connectcrypto.NewService(&testutil.FakeKEK{KEK: make([]byte, connectcrypto.KEKSize)})
mgrWithBrokenCore := webhooksub.NewManager(env.Pool, cryptoSvc, webhookclient.New(brokenCore.URL, "svc-token-test"), "https://connect.example.test/connector-webhooks/deliveries")
if err := mgrWithBrokenCore.Unsubscribe(context.Background(), "acme", "testcrm", "dms.document.archived"); err == nil {
+2 -7
View File
@@ -14,14 +14,9 @@ import (
dmscrypto "gitea.perlbach24.de/scripte/nexarch/dms/internal/crypto"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
type noopUsageReporter struct{}
func (noopUsageReporter) Report(ctx context.Context, tenantSlug, metric string, delta int64) error {
@@ -93,7 +88,7 @@ func setupTest(t *testing.T) *testEnv {
}
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x44}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x44}, dmscrypto.KEKSize)})
return &testEnv{pool: pool, storage: storageSvc, crypto: cryptoSvc, userID: userID}
}
+2 -7
View File
@@ -15,14 +15,9 @@ import (
dmscrypto "gitea.perlbach24.de/scripte/nexarch/dms/internal/crypto"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
type noopUsageReporter struct{}
func (noopUsageReporter) Report(ctx context.Context, tenantSlug, metric string, delta int64) error {
@@ -77,7 +72,7 @@ func setupTest(t *testing.T) (*httptest.Server, *pgxpool.Pool, *storage.Service,
})
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x33}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x33}, dmscrypto.KEKSize)})
server := NewServer(pool, storageSvc, cryptoSvc, "acme")
mux := http.NewServeMux()
+2 -7
View File
@@ -22,14 +22,9 @@ import (
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testaudit"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
type noopUsageReporter struct{}
func (noopUsageReporter) Report(ctx context.Context, tenantSlug, metric string, delta int64) error {
@@ -84,7 +79,7 @@ func setupTest(t *testing.T, ttl time.Duration) (*testEnv, string) {
t.Cleanup(func() { _, _ = pool.Exec(context.Background(), `TRUNCATE file_revisions, documents, users CASCADE`) })
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("storage-secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x11}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x11}, dmscrypto.KEKSize)})
server := NewServer(pool, storageSvc, cryptoSvc, "acme", &DocumentOwnerChecker{Pool: pool}, []byte("download-secret"), ttl)
mux := http.NewServeMux()
+2 -7
View File
@@ -20,14 +20,9 @@ import (
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testaudit"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
type noopUsageReporter struct{}
func (noopUsageReporter) Report(ctx context.Context, tenantSlug, metric string, delta int64) error {
@@ -107,7 +102,7 @@ func setupTest(t *testing.T) (*testEnv, string) {
storageDir := t.TempDir()
storageSvc := storage.NewService(storage.NewLocalDriver(storageDir, []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
queue := jobqueue.NewQueue(pool, 5*time.Minute)
proc := &Processor{Pool: pool, Storage: storageSvc, Crypto: cryptoSvc, TenantSlug: "acme", Permissions: &ownerChecker{pool: pool}}
worker := jobqueue.NewWorker(queue, "test-export-worker", []string{JobType}, time.Millisecond, proc.Handler)
+2 -7
View File
@@ -17,14 +17,9 @@ import (
dmscrypto "gitea.perlbach24.de/scripte/nexarch/dms/internal/crypto"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
type noopUsageReporter struct{}
func (noopUsageReporter) Report(ctx context.Context, tenantSlug, metric string, delta int64) error {
@@ -104,7 +99,7 @@ func setupTest(t *testing.T) (*pgxpool.Pool, *storage.Service, *dmscrypto.Servic
})
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x66}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x66}, dmscrypto.KEKSize)})
var userID string
if err := pool.QueryRow(ctx, `INSERT INTO users (email, name) VALUES ($1, 'A') RETURNING id`, fmt.Sprintf("malwarescan-%d@example.test", time.Now().UnixNano())).Scan(&userID); err != nil {
+3 -10
View File
@@ -16,16 +16,9 @@ import (
dmscrypto "gitea.perlbach24.de/scripte/nexarch/dms/internal/crypto"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
// fakeKEKProvider liefert einen fest hinterlegten Tenant-KEK, analog zum
// Fake in dms/internal/upload (dort nicht exportiert).
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
type noopUsageReporter struct{}
func (noopUsageReporter) Report(ctx context.Context, tenantSlug, metric string, delta int64) error {
@@ -149,7 +142,7 @@ func setupMigratorTest(t *testing.T) (*Migrator, *pgxpool.Pool, *storage.LocalDr
driver := storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0)
storageSvc := storage.NewService(driver, noopUsageReporter{}, "acme-test")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
migrator := NewMigrator(pool, newSyntheticSource(), staticUserResolver{userID: userID}, storageSvc, cryptoSvc, "acme-test")
return migrator, pool, driver, userID
@@ -232,7 +225,7 @@ func TestMigrateAll_AkzeptanzkriteriumKonsistenteVerknuepfung(t *testing.T) {
if err := pool.QueryRow(ctx, `SELECT wrapped_dek FROM file_revisions WHERE id = $1`, currentRevisionID).Scan(&wrappedDEK); err != nil {
t.Fatalf("wrapped_dek lesen: %v", err)
}
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
plainReader, err := cryptoSvc.Open(ctx, "acme-test", wrappedDEK, bytes.NewReader(ciphertext))
if err != nil {
t.Fatalf("entschluesseln: %v", err)
+2 -7
View File
@@ -18,14 +18,9 @@ import (
"gitea.perlbach24.de/scripte/nexarch/dms/internal/jobqueue"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
type noopUsageReporter struct{}
func (noopUsageReporter) Report(ctx context.Context, tenantSlug, metric string, delta int64) error {
@@ -98,7 +93,7 @@ func setupTest(t *testing.T) *testEnv {
}
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
queue := jobqueue.NewQueue(pool, time.Minute)
return &testEnv{
+2 -7
View File
@@ -22,14 +22,9 @@ import (
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testaudit"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
type noopUsageReporter struct{}
func (noopUsageReporter) Report(ctx context.Context, tenantSlug, metric string, delta int64) error {
@@ -104,7 +99,7 @@ func setupTest(t *testing.T, identity *SigningIdentity, tsaURL string) *testEnv
}
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
return &testEnv{
pool: pool, storage: storageSvc, crypto: cryptoSvc, userID: userID,
+14
View File
@@ -0,0 +1,14 @@
// Package testutil buendelt Test-Doubles, die identisch in mehreren
// dms/internal-Paketen dupliziert waren (Fable-Review auf Code-Dopplung).
package testutil
import "context"
// FakeKEKProvider ist ein Test-Double fuer das KEKProvider-Interface
// (crypto.NewService braucht einen) -- liefert immer denselben festen
// Schluessel, unabhaengig vom Tenant.
type FakeKEKProvider struct{ KEK []byte }
func (f *FakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.KEK, nil
}
+2 -7
View File
@@ -21,14 +21,9 @@ import (
"gitea.perlbach24.de/scripte/nexarch/dms/internal/jobqueue"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
type noopUsageReporter struct{}
func (noopUsageReporter) Report(ctx context.Context, tenantSlug, metric string, delta int64) error {
@@ -104,7 +99,7 @@ func setupTest(t *testing.T) *testEnv {
}
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
queue := jobqueue.NewQueue(pool, time.Minute)
return &testEnv{
+2 -10
View File
@@ -19,17 +19,9 @@ import (
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testaudit"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
// fakeKEKProvider liefert einen fest hinterlegten Tenant-KEK — dieselbe
// Fixture wie in internal/crypto, hier lokal dupliziert, da Testhilfen
// nicht paketuebergreifend exportiert sind.
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
func setupServiceTest(t *testing.T) (*Service, *pgxpool.Pool, string) {
t.Helper()
dsn := os.Getenv("TEST_TENANT_DSN")
@@ -99,7 +91,7 @@ func setupServiceTest(t *testing.T) (*Service, *pgxpool.Pool, string) {
sessions := NewSessionStore(pool)
staging := NewStaging(t.TempDir())
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x11}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x11}, dmscrypto.KEKSize)})
validator := NewValidator(10*1024*1024, []string{"application/pdf", "text/plain"})
svc := NewService(pool, sessions, staging, storageSvc, cryptoSvc, validator, "acme")
+2 -7
View File
@@ -18,14 +18,9 @@ import (
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/upload"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
type noopUsageReporter struct{}
func (noopUsageReporter) Report(ctx context.Context, tenantSlug, metric string, delta int64) error {
@@ -73,7 +68,7 @@ func setupTest(t *testing.T) (*httptest.Server, string) {
sessions := upload.NewSessionStore(pool)
staging := upload.NewStaging(t.TempDir())
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
validator := upload.NewValidator(10*1024*1024, []string{"application/pdf", "text/plain"})
svc := upload.NewService(pool, sessions, staging, storageSvc, cryptoSvc, validator, "acme")
@@ -21,6 +21,7 @@ import (
"gitea.perlbach24.de/scripte/nexarch/dms/internal/migrate"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/upload"
)
@@ -72,7 +73,7 @@ func setupInt19Test(t *testing.T, maxSizeBytes int64) (*httptest.Server, string,
sessions := upload.NewSessionStore(pool)
staging := upload.NewStaging(t.TempDir())
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x22}, dmscrypto.KEKSize)})
// Gleiche Positivliste wie ein echter mobiler Erfassungskanal: nur der
// vom Kamera-Capture-Code tatsaechlich erzeugte MIME-Typ ist erlaubt.
validator := upload.NewValidator(maxSizeBytes, []string{"image/jpeg"})
+2 -1
View File
@@ -15,6 +15,7 @@ import (
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testaudit"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
// Akzeptanzkriterium 1: Textunterschiede werden zeilenweise geliefert.
@@ -189,7 +190,7 @@ func setupDiffTest(t *testing.T) (*pgxpool.Pool, *storage.Service, *dmscrypto.Se
})
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x77}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x77}, dmscrypto.KEKSize)})
var userID string
if err := pool.QueryRow(ctx, `INSERT INTO users (email, name) VALUES ($1, 'A') RETURNING id`, fmt.Sprintf("diff-%d@example.test", time.Now().UnixNano())).Scan(&userID); err != nil {
+2 -7
View File
@@ -15,14 +15,9 @@ import (
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testaudit"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
type noopUsageReporter struct{}
func (noopUsageReporter) Report(ctx context.Context, tenantSlug, metric string, delta int64) error {
@@ -85,7 +80,7 @@ func setupTest(t *testing.T) (*testEnv, string, string) {
}
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x44}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x44}, dmscrypto.KEKSize)})
return &testEnv{pool: pool, storage: storageSvc, crypto: cryptoSvc}, userA, userB
}
+2 -7
View File
@@ -19,14 +19,9 @@ import (
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testaudit"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/versioning"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
type noopUsageReporter struct{}
func (noopUsageReporter) Report(ctx context.Context, tenantSlug, metric string, delta int64) error {
@@ -90,7 +85,7 @@ func setupTest(t *testing.T) (*testEnv, string, string) {
}
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x55}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x55}, dmscrypto.KEKSize)})
server := NewServer(pool, storageSvc, cryptoSvc, "acme", &OwnerChecker{Pool: pool})
mux := http.NewServeMux()
+3 -8
View File
@@ -17,6 +17,7 @@ import (
"gitea.perlbach24.de/scripte/nexarch/dms/internal/storage"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testdb"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/upload"
"gitea.perlbach24.de/scripte/nexarch/dms/internal/testutil"
)
// allowAll ersetzt den Tenant-Guard in den Tests der Import-Pipeline (INT-08); die Zuordnung prueft guard_test.go.
@@ -24,12 +25,6 @@ type allowAll struct{}
func (allowAll) Check(context.Context, string) error { return nil }
type fakeKEKProvider struct{ kek []byte }
func (f *fakeKEKProvider) TenantKEK(ctx context.Context, tenantSlug string) ([]byte, error) {
return f.kek, nil
}
type noopUsageReporter struct{}
func (noopUsageReporter) Report(ctx context.Context, tenantSlug, metric string, delta int64) error {
@@ -106,7 +101,7 @@ func setupTest(t *testing.T) (svc *upload.Service, pool *pgxpool.Pool, userID st
sessions := upload.NewSessionStore(pool)
staging := upload.NewStaging(t.TempDir())
storageSvc := storage.NewService(storage.NewLocalDriver(t.TempDir(), []byte("secret"), "https://files.example.test", 0), noopUsageReporter{}, "acme")
cryptoSvc := dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x11}, dmscrypto.KEKSize)})
cryptoSvc := dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x11}, dmscrypto.KEKSize)})
validator := upload.NewValidator(10*1024*1024, nil)
svc = upload.NewService(pool, sessions, staging, storageSvc, cryptoSvc, validator, "acme")
@@ -241,5 +236,5 @@ func newStorageSvc(t *testing.T) *storage.Service {
}
func newCryptoSvc() *dmscrypto.Service {
return dmscrypto.NewService(&fakeKEKProvider{kek: bytes.Repeat([]byte{0x11}, dmscrypto.KEKSize)})
return dmscrypto.NewService(&testutil.FakeKEKProvider{KEK: bytes.Repeat([]byte{0x11}, dmscrypto.KEKSize)})
}