// Copyright 2024 Matthew Rich . All rights reserved. package resource import ( "context" "github.com/stretchr/testify/assert" "testing" "fmt" "decl/internal/data" "decl/internal/folio" "decl/internal/codec" "decl/internal/ext" "log" "io" "os" "bytes" "github.com/ProtonMail/go-crypto/openpgp" "github.com/ProtonMail/go-crypto/openpgp/armor" "log/slog" "path/filepath" ) var mockKeyRingPassphraseConfig MockConfigValueGetter = func(key string) (any, error) { switch key { case "passphrase": return "foo", nil } return nil, fmt.Errorf("%w: %s", data.ErrUnknownConfigurationKey, key) } func DataKeyRing(uri folio.URI) (folio.ReferenceMapper[*folio.Declaration], folio.URI) { var err error var reader io.ReadCloser searchPath := folio.NewSearchPath(folio.ConfigKey("system.importpath").GetStringSlice()) if u := uri.Parse().(*folio.ParsedURI); u != nil { projectPath := filepath.Dir(filepath.Join(u.Hostname(), u.Path)) if err := searchPath.AddPath(projectPath); err != nil { panic(err) } } if reader, err = uri.ContentReaderStream(); err == nil { keyRingDecl := folio.NewDeclaration() if err = keyRingDecl.LoadReader(reader, codec.FormatYaml); err == nil { keyRing := keyRingDecl.Resource() testKeyRingResource := keyRing.(*OpenPGPKeyRing) testKeyRingResource.KeyRingRef.FindIn(searchPath) keyRing.UseConfig(mockKeyRingPassphraseConfig) keyRing.Read(context.Background()) if testKeyRingResource.entityList[0].PrivateKey == nil { log.Fatal("Keyring does not contain a private key") } testKeyRingResource.Resources = folio.NewResourceMapper() testKeyRingResource.Resources.Set(folio.URI(keyRing.URI()), keyRingDecl) return testKeyRingResource.Resources, folio.URI(testKeyRingResource.URI()) } } log.Fatal(err) return nil, "" } func NewTestUserKeys(name string, comment string, email string) (folio.ReferenceMapper[*folio.Declaration], folio.URI) { uri := fmt.Sprintf("openpgp-keyring://%s/%s/%s", name, comment, email) keyRingDecl := folio.NewDeclaration() keyRingDecl.NewResource(&uri) ctx := context.Background() declarationAttributes := fmt.Sprintf(` name: %s comment: %s email: %s keyringref: file://%s/keyring_%s.asc `, name, comment, email, string(TempDir), name) testKeyRing := keyRingDecl.Resource() if e := testKeyRing.LoadString(declarationAttributes, codec.FormatYaml); e != nil { log.Fatal(e) } testKeyRing.UseConfig(mockKeyRingPassphraseConfig) if err := testKeyRing.Create(ctx); err != nil { log.Fatal(err) } testKeyRingResource := testKeyRing.(*OpenPGPKeyRing) if testKeyRingResource.entityList[0].PrivateKey == nil { log.Fatal("Keyring does not contain a private key") } testKeyRingResource.Resources = folio.NewResourceMapper() testKeyRingResource.Resources.Set(folio.URI(uri), keyRingDecl) return testKeyRingResource.Resources, folio.URI(uri) } func KeyRingTestUser1() (folio.ReferenceMapper[*folio.Declaration], folio.URI) { name := "TestUser1" comment := "TestUser1" email := "testuser@rosskeen.house" if e := TempDir.CreateFile("keyring_TestUser1.asc", ` -----BEGIN PGP PRIVATE KEY BLOCK----- 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 =BAfD -----END PGP PRIVATE KEY BLOCK----- -----BEGIN PGP PUBLIC KEY BLOCK----- xsBNBGhI/VUBCADDVSm3mKY5JsncMMJFV0zELMrmip7dkK3vvMvVWVmMHiC4akDH WPxUdWNQPjE2e5HGF9Ebg0c7gu634VG470MnTzFdPV6f5zA+yJfdKrLq7gpl9QGW jFLIeK/l4xc+MIpOE1rD9WqYUUw2IYY8YANYq4yB36rq41VuZps/adI9Go5IhfcU 3SVb7o7pa/gWE0FVu9ze31j2agC8FIKHgB++7bmYgbAQz5Qi1qgtG0Kn25QUacJ6 Akm2+h4w3SQCR6HLRV2BO29x9mFBszf2KQ7DW2VNiGyUuQQ3m8v2ZidG/11ff6U6 ad5tvr/8sYr5jOnKEJyDP9v9yQ04cU94GmsPABEBAAHNL1Rlc3RVc2VyMSAoVGVz dFVzZXIxKSA8dGVzdHVzZXJAcm9zc2tlZW4uaG91c2U+wsCKBBMBCAA+BQJoSP1V CRDfB5I2FtNl1xYhBADOnA8Aah3FXyl/m98HkjYW02XXAhsDAh4BAhkBAgsHAhUI AxYAAgMnBwIAAGKLB/9whwgfLkoTYI+Q0Te2uZXl7FPyW0t4tbUSoI1aiVw+ymND V+wuqYsjYDob2MyK/TAFkSCqZhBIRbGLRJtwzQwkF/amGuelHSSBX3LdxK/sp2UU +zv/NBEP1LlUNKchuxpdBPYjKHdbOLPoKqFfdCujSxpWTIeKCwvnDtuP+PlsjUgc afxMx+cVwe77AZ1Fi5CBD9Dr7nNsLovywrSiszyVh5eT0pbcu8Elf5oYQNT1q3ms aqrw95shlGQiwVgrfTvRCDeZnKafHwMUoh48otsNI9aS0HpChi+JNd+PLe/Wlsj5 x+q0sHc+5/24zQvN0Wx9fPE4/7z8Pr+CUhAxjI7hzsBNBGhI/VUBCACfahoi2GRx OfOqJ4ZN8Te+4bJeOQdzTofAisfCU736q+MvEKtAuY72vzWdERWpn7XABmtkfII8 Xyya8iHKuEGCETy0YoZ15GLBgSHhLnlN2U/4BkrUjGvUjZWquW22gfFB1q8ZdSGw pg8hrspY/b+nnAGdawq+hfE6YRQTmG5tkBrctxfxglBnKzezmL1a3arTHWf2SRlL eAWNI4sACryP/5plD6+9Z9YXTKeDlXnga6BzB80y7F2g0cPdtX20dWAGx4irq2I2 SxlABvWMZrdm2Upr6yLHD2zTpbf1FkKFUw9j0lrL1fMq0/j9zbKJsTh6CtOlF04s AeoEV9SZ36GvABEBAAHCwHYEGAEIACoFAmhI/VUJEN8HkjYW02XXFiEEAM6cDwBq HcVfKX+b3weSNhbTZdcCGwwAAFxWB/9Af7qpYKldDz5iNYQluFoPfyHAVlOpiakf hvnu7hijTEgB1frByKu2m+k4m7gANBgfWldsYi1feWBVn6fspXuCc0k7opmQgol7 ueTrsGnNB7U0l14HcKSTLZ2c/Jt7ZS6aXXjxpYPq0/5lt8+5sRkXxHI9HhAx6gK/ RJCNITRt/V/gT4YWWbz8VHgkPIfHFsjr8brVhm4V/+JKZAG4eSNQp4QrTpdIjdfa 1rd91qffyrWhPNTQErE2jFOXSU/OojdDjGJ7pwr0qj4FHACVL3/oqYog2NrUWf92 QcwwWrEZNZUpJEMUB5q+tOoZ40ll0A8lsvABULZDqWveYpRQF+rQ =jBvZ -----END PGP PUBLIC KEY BLOCK----- `); e != nil { log.Fatal(e) } uri := fmt.Sprintf("openpgp-keyring://%s/%s/%s", name, comment, email) keyRingDecl := folio.NewDeclaration() keyRingDecl.NewResource(&uri) ctx := context.Background() declarationAttributes := fmt.Sprintf(` name: %s comment: %s email: %s keyringref: file://%s/keyring_%s.asc `, name, comment, email, string(TempDir), name) testKeyRing := keyRingDecl.Resource() if e := testKeyRing.LoadString(declarationAttributes, codec.FormatYaml); e != nil { log.Fatal(e) } testKeyRing.UseConfig(MockConfigValueGetter(func(key string) (any, error) { switch key { case "passphrase": return "foo", nil } return nil, fmt.Errorf("%w: %s", data.ErrUnknownConfigurationKey, key) })) if _, err := testKeyRing.Read(ctx); err != nil { log.Fatal(err) } testKeyRingResource := testKeyRing.(*OpenPGPKeyRing) testKeyRingResource.Resources = folio.NewResourceMapper() if testKeyRingResource.entityList[0].PrivateKey == nil { log.Fatal("Keyring does not contain a private key") } /* return TestRefMapper[*folio.Declaration](func(key string) (*folio.Declaration, bool) { switch key { case uri: slog.Info("KEYRING", "name", name, "addr", testKeyRing.(*OpenPGPKeyRing).entityList[0].PrivateKey) return keyRingDecl, true } return nil, false }), folio.URI(uri) */ testKeyRingResource.Resources.Set(folio.URI(uri), keyRingDecl) return testKeyRingResource.Resources, folio.URI(uri) } func DataTestKeyRing(keyRingPath string) (folio.ReferenceMapper[*folio.Declaration], folio.URI) { keyData, err := os.ReadFile(keyRingPath) if err != nil { panic(err) } keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(keyData)) if err != nil { panic(err) } var name, comment, email string for _, entity := range keyring { for _, identity := range entity.Identities { if identity.UserId != nil { name = identity.UserId.Name comment = identity.UserId.Comment email = identity.UserId.Email } } } uri := fmt.Sprintf("openpgp-keyring://%s/%s/%s", name, comment, email) keyRingDecl := folio.NewDeclaration() keyRingDecl.NewResource(&uri) ctx := context.Background() declarationAttributes := fmt.Sprintf(` name: %s comment: %s email: %s keyringref: file://%s `, name, comment, email, keyRingPath) testKeyRing := keyRingDecl.Resource() if e := testKeyRing.LoadString(declarationAttributes, codec.FormatYaml); e != nil { log.Fatal(e) } testKeyRing.UseConfig(MockConfigValueGetter(func(key string) (any, error) { switch key { case "passphrase": return "foo", nil } return nil, fmt.Errorf("%w: %s", data.ErrUnknownConfigurationKey, key) })) if _, err := testKeyRing.Read(ctx); err != nil { log.Fatal(err) } testKeyRingResource := testKeyRing.(*OpenPGPKeyRing) testKeyRingResource.Resources = folio.NewResourceMapper() if testKeyRingResource.entityList[0].PrivateKey == nil { log.Fatal("Keyring does not contain a private key") } testKeyRingResource.Resources.Set(folio.URI(uri), keyRingDecl) return testKeyRingResource.Resources, folio.URI(uri) } func TestNewOpenPGPSignatureResource(t *testing.T) { assert.NotNil(t, NewOpenPGPSignature()) } func TestSigningEntity(t *testing.T) { m, keyRingUri := NewTestUserKeys("TestUser5", "TestUser5", "testuser5@rosskeen.house") assert.NotNil(t, m) assert.Equal(t, folio.URI("openpgp-keyring://TestUser5/TestUser5/testuser5@rosskeen.house"), keyRingUri) assert.Nil(t, TempDir.CreateFile("signing-test.txt", "test data")) assert.FileExists(t, fmt.Sprintf("%s/keyring_TestUser5.asc", TempDir)) testUserKeyRingResource := folio.Dereference(keyRingUri, m) assert.NotNil(t, testUserKeyRingResource) assert.NotNil(t, testUserKeyRingResource.Resource().(*OpenPGPKeyRing).entityList[0].PrivateKey) declarationAttributes := fmt.Sprintf(` keyringref: uri: %s sourceref: uri: file://%s/signing-test.txt `, string(keyRingUri), string(TempDir)) testSignature := NewOpenPGPSignature() e := testSignature.LoadString(declarationAttributes, codec.FormatYaml) assert.Nil(t, e) testSignature.Resources = m testSignature.UseConfig(MockConfigValueGetter(func(key string) (any, error) { switch key { case "passphrase": return "foo", nil } return nil, fmt.Errorf("%w: %s", data.ErrUnknownConfigurationKey, key) })) assert.False(t, testSignature.KeyRingRef.IsEmpty()) slog.Info("TestSigningEntity", "keyringref", testSignature.KeyRingRef, "resourcemap", testSignature.Resources) keyRingResource := testSignature.KeyRingRef.Lookup(testSignature.Resources) assert.NotNil(t, keyRingResource) ringFileStream, streamErr := keyRingResource.ContentReaderStream() assert.Nil(t, streamErr) assert.NotNil(t, ringFileStream) assert.Nil(t, testSignature.SigningEntity()) assert.NotNil(t, testSignature.entityList) assert.Len(t, testSignature.entityList, 1) assert.NotNil(t, testSignature.entityList[0].PrivateKey) } func TestSign(t *testing.T) { //ctx := context.Background() m, keyRingUri := NewTestUserKeys("TestUser2", "TestUser2", "testuser2@rosskeen.house") assert.NotNil(t, m) assert.Equal(t, folio.URI("openpgp-keyring://TestUser2/TestUser2/testuser2@rosskeen.house"), keyRingUri) assert.Nil(t, TempDir.CreateFile("sign-test.txt", "test data")) declarationAttributes := fmt.Sprintf(` keyringref: uri: %s sourceref: uri: file://%s/sign-test.txt `, string(keyRingUri), string(TempDir)) testSignature := NewOpenPGPSignature() testSignature.Resources = m assert.Nil(t, testSignature.LoadString(declarationAttributes, codec.FormatYaml)) testSignature.UseConfig(MockConfigValueGetter(func(key string) (any, error) { switch key { case "passphrase": return "foo", nil } return nil, fmt.Errorf("%w: %s", data.ErrUnknownConfigurationKey, key) })) assert.Nil(t, testSignature.SigningEntity()) sourceReadStream, err := testSignature.SourceRef.Lookup(testSignature.Resources).ContentReaderStream() var signatureStream, armoredWriter io.WriteCloser assert.True(t, testSignature.SignatureRef.IsEmpty()) var signatureContent bytes.Buffer signatureStream = ext.WriteNopCloser(&signatureContent) defer func() { testSignature.Signature = signatureContent.String() }() if armoredWriter, err = armor.Encode(signatureStream, openpgp.SignatureType, nil); err != nil { err = fmt.Errorf("%w: %w", ErrArmoredWriterFailed, err) } defer armoredWriter.Close() slog.Info("TESTSIGN KEYRING", "name", "TestUser2", "addr", testSignature.KeyRingRef.Lookup(testSignature.Resources).(*OpenPGPKeyRing)) assert.Len(t, testSignature.entityList, 1) slog.Info("Signing Entity", "entity", testSignature.entityList[0]) assert.NotNil(t, testSignature.entityList[0].PrivateKey) assert.Nil(t, testSignature.Sign(sourceReadStream, armoredWriter)) } func TestCreateSignature(t *testing.T) { ctx := context.Background() m, keyRingUri := NewTestUserKeys("TestUser3", "TestUser3", "testuser3@rosskeen.house") assert.NotNil(t, m) assert.Equal(t, folio.URI("openpgp-keyring://TestUser3/TestUser3/testuser3@rosskeen.house"), keyRingUri) assert.Nil(t, TempDir.CreateFile("test3.txt", "test data\n")) declarationAttributes := fmt.Sprintf(` keyringref: uri: %s sourceref: uri: file://%s/test3.txt `, string(keyRingUri), string(TempDir)) testSignature := NewOpenPGPSignature() testSignature.Resources = m testSignature.UseConfig(MockConfigValueGetter(func(key string) (any, error) { switch key { case "passphrase": return "foo", nil } return nil, fmt.Errorf("%w: %s", data.ErrUnknownConfigurationKey, key) })) e := testSignature.LoadString(declarationAttributes, codec.FormatYaml) assert.Nil(t, e) err := testSignature.Create(ctx) assert.Nil(t, err) assert.Greater(t, len(testSignature.entityList), 0) assert.Contains(t, testSignature.entityList[0].Identities, "TestUser3 (TestUser3) ") assert.NotContains(t, testSignature.Signature, "-----END PGP PUBLIC KEY BLOCK-----") assert.NotContains(t, testSignature.Signature, "-----END PGP PRIVATE KEY BLOCK-----") assert.Contains(t, testSignature.Signature, "-----END PGP SIGNATURE-----") } func TestReadSignature(t *testing.T) { ctx := context.Background() assert.Nil(t, TempDir.CreateFile("read-test.txt", "test data\n")) m, keyRingUri := KeyRingTestUser1() assert.NotNil(t, m) assert.Equal(t, folio.URI("openpgp-keyring://TestUser1/TestUser1/testuser@rosskeen.house"), keyRingUri) declarationAttributes := fmt.Sprintf(` keyringref: uri: %s sourceref: uri: file://%s/read-test.txt signature: |- -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEAM6cDwBqHcVfKX+b3weSNhbTZdcFAmhQtmMACgkQ3weSNhbT ZddNPAf/ZSKVOUXVlIBgXMsw2RqVWYkOzyuWADeOq6P1UHlRN0xxSmOFnHukxstL zTa7KSpf5y3/DKRSTWldAy8WYFr0mx5hoDy5c83OYZo2oUtFsVYifol4JfZeF+ij 6a2trW17VjtKYzwpSTt/SAaTxKj/6oVevpWykOPfg6V3CCLfnVEuBMhotU91ngbg wh3R3K7LrVVJ6kYI4RKUeBIx280JZMG0sZ/AuwUdWG6KFavGMbHVzHHD2PMwT53t xJ5kzWyS9ZWws8r/B33GM9szHplXulhETsd1S3x0/R2MoVcHeAaAa6JwD0y0Kxu6 MuQM3twP32lK4UUqNx4oPHzU5gbirA== =+dVO -----END PGP SIGNATURE----- ` , string(keyRingUri), string(TempDir)) testSignature := NewOpenPGPSignature() testSignature.Resources = m testSignature.UseConfig(MockConfigValueGetter(func(key string) (any, error) { switch key { case "passphrase": return "foo", nil } return nil, fmt.Errorf("%w: %s", data.ErrUnknownConfigurationKey, key) })) e := testSignature.LoadDecl(declarationAttributes) assert.Nil(t, e) y, err := testSignature.Read(ctx) assert.Nil(t, err) assert.NotNil(t, y) assert.Greater(t, len(testSignature.entityList), 0) assert.Contains(t, testSignature.entityList[0].Identities, "TestUser1 (TestUser1) ") } func TestSignatureBlock(t *testing.T) { assert.Nil(t, TempDir.CreateFile("block-test.txt", "test data\n")) m, keyRingUri := KeyRingTestUser1() assert.NotNil(t, m) assert.Equal(t, folio.URI("openpgp-keyring://TestUser1/TestUser1/testuser@rosskeen.house"), keyRingUri) declarationAttributes := fmt.Sprintf(` keyringref: uri: %s sourceref: uri: file://%s/block-test.txt signature: |- -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEAM6cDwBqHcVfKX+b3weSNhbTZdcFAmhQtmMACgkQ3weSNhbT ZddNPAf/ZSKVOUXVlIBgXMsw2RqVWYkOzyuWADeOq6P1UHlRN0xxSmOFnHukxstL zTa7KSpf5y3/DKRSTWldAy8WYFr0mx5hoDy5c83OYZo2oUtFsVYifol4JfZeF+ij 6a2trW17VjtKYzwpSTt/SAaTxKj/6oVevpWykOPfg6V3CCLfnVEuBMhotU91ngbg wh3R3K7LrVVJ6kYI4RKUeBIx280JZMG0sZ/AuwUdWG6KFavGMbHVzHHD2PMwT53t xJ5kzWyS9ZWws8r/B33GM9szHplXulhETsd1S3x0/R2MoVcHeAaAa6JwD0y0Kxu6 MuQM3twP32lK4UUqNx4oPHzU5gbirA== =+dVO -----END PGP SIGNATURE----- ` , string(keyRingUri), string(TempDir)) testSignature := NewOpenPGPSignature() testSignature.Resources = m testSignature.UseConfig(MockConfigValueGetter(func(key string) (any, error) { switch key { case "passphrase": return "foo", nil } return nil, fmt.Errorf("%w: %s", data.ErrUnknownConfigurationKey, key) })) e := testSignature.LoadDecl(declarationAttributes) assert.Nil(t, e) err := testSignature.DecodeSignatureBlock() assert.Nil(t, err) } func TestVerifySignature(t *testing.T) { ctx := context.Background() assert.Nil(t, TempDir.CreateFile("verify-test.txt", "test data\n")) m, keyRingUri := KeyRingTestUser1() assert.NotNil(t, m) assert.Equal(t, folio.URI("openpgp-keyring://TestUser1/TestUser1/testuser@rosskeen.house"), keyRingUri) declarationAttributes := fmt.Sprintf(` keyringref: uri: %s sourceref: uri: file://%s/verify-test.txt signature: |- -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEAM6cDwBqHcVfKX+b3weSNhbTZdcFAmhQtmMACgkQ3weSNhbT ZddNPAf/ZSKVOUXVlIBgXMsw2RqVWYkOzyuWADeOq6P1UHlRN0xxSmOFnHukxstL zTa7KSpf5y3/DKRSTWldAy8WYFr0mx5hoDy5c83OYZo2oUtFsVYifol4JfZeF+ij 6a2trW17VjtKYzwpSTt/SAaTxKj/6oVevpWykOPfg6V3CCLfnVEuBMhotU91ngbg wh3R3K7LrVVJ6kYI4RKUeBIx280JZMG0sZ/AuwUdWG6KFavGMbHVzHHD2PMwT53t xJ5kzWyS9ZWws8r/B33GM9szHplXulhETsd1S3x0/R2MoVcHeAaAa6JwD0y0Kxu6 MuQM3twP32lK4UUqNx4oPHzU5gbirA== =+dVO -----END PGP SIGNATURE----- ` , string(keyRingUri), string(TempDir)) testSignature := NewOpenPGPSignature() testSignature.Resources = m testSignature.UseConfig(MockConfigValueGetter(func(key string) (any, error) { switch key { case "passphrase": return "foo", nil } return nil, fmt.Errorf("%w: %s", data.ErrUnknownConfigurationKey, key) })) e := testSignature.LoadDecl(declarationAttributes) assert.Nil(t, e) y, err := testSignature.Read(ctx) assert.Nil(t, err) assert.NotNil(t, y) assert.Greater(t, len(testSignature.entityList), 0) assert.Contains(t, testSignature.entityList[0].Identities, "TestUser1 (TestUser1) ") assert.Equal(t, "DF07923616D365D7", fmt.Sprintf("%X", testSignature.entityList[0].PrimaryKey.KeyId)) sourceReadStream, sourceReadStreamErr := testSignature.SourceRef.ContentReaderStream() assert.Nil(t, sourceReadStreamErr) assert.Nil(t, testSignature.DecodeSignatureBlock()) assert.Nil(t, testSignature.Verify(sourceReadStream)) sourceReadStream.Close() assert.Nil(t, testSignature.DecodeSignatureBlock()) sourceReadStream2, sourceReadStreamErr2 := testSignature.SourceRef.ContentReaderStream() assert.Nil(t, sourceReadStreamErr2) assert.Nil(t, testSignature.Verify(sourceReadStream2)) } func TestVerifyDocumentSignature(t *testing.T) { ctx := context.Background() assert.Nil(t, TempDir.CreateFile("verify-test.txt", "test data\n")) m, keyRingUri := DataKeyRing("file://../../tests/data/openpgp-keyring/keyring_jx.yaml") assert.NotNil(t, m) assert.Equal(t, folio.URI("openpgp-keyring://TestUser1/TestUser1/testuser@rosskeen.house"), keyRingUri) // load a document docURI := folio.URI("file://../../examples/signed/ubuntu-dev-read.jx.yaml") r, readerErr := docURI.ContentReaderStream() assert.Nil(t, readerErr) assert.NotNil(t, r) doc := folio.DocumentRegistry.NewDocument(docURI) assert.Nil(t, doc.LoadReader(r, codec.FormatYaml)) declarationAttributes := fmt.Sprintf(` keyringref: uri: %s sourceref: uri: %s type: document ` , string(keyRingUri), string(docURI)) testSignature := NewOpenPGPSignature() testSignature.Resources = m testSignature.UseConfig(mockKeyRingPassphraseConfig) e := testSignature.LoadDecl(declarationAttributes) assert.Nil(t, e) createErr := testSignature.Create(ctx) assert.Nil(t, createErr) assert.Greater(t, len(testSignature.entityList), 0) assert.Contains(t, testSignature.entityList[0].Identities, "TestUser1 (TestUser1) ") y, err := testSignature.Read(ctx) // XXX throws an error if no signature is present assert.Nil(t, err) assert.NotNil(t, y) assert.Greater(t, len(testSignature.entityList), 0) assert.Contains(t, testSignature.entityList[0].Identities, "TestUser1 (TestUser1) ") assert.Equal(t, "FAED7F3BB05EF687", fmt.Sprintf("%X", testSignature.entityList[0].PrimaryKey.KeyId)) sourceReadStream, sourceReadStreamErr := testSignature.SourceRef.Reader() assert.Nil(t, sourceReadStreamErr) assert.Nil(t, testSignature.DecodeSignatureBlock()) assert.Nil(t, testSignature.Verify(sourceReadStream)) sourceReadStream.Close() assert.Nil(t, testSignature.DecodeSignatureBlock()) sourceReadStream2, sourceReadStreamErr2 := testSignature.SourceRef.Reader() assert.Nil(t, sourceReadStreamErr2) assert.Nil(t, testSignature.Verify(sourceReadStream2)) }