Skip to content

Commit fcabebe

Browse files
committed
Add e2e test suite to evidence
1 parent 2adc35a commit fcabebe

File tree

5 files changed

+420
-7
lines changed

5 files changed

+420
-7
lines changed

tests/e2e/local/docker-compose.yml

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ services:
4848
JF_EVIDENCE_NAVIGATION_ENABLED: "true"
4949
JF_EVIDENCE_ENABLED: "false" # Evidence runs as separate service
5050

51+
# AppTrust integration
52+
JF_ARTIFACTORY_APPTRUST_ENABLED: "true"
53+
JF_APPTRUST_NAVIGATION_ENABLED: "true"
54+
JF_APPTRUST_ENABLED: "false" # AppTrust runs as separate service
55+
56+
# Unified Policy integration
57+
JF_ARTIFACTORY_UNIFIED_POLICY_ENABLED: "true"
58+
JF_UNIFIED_POLICY_NAVIGATION_ENABLED: "true"
59+
JF_UNIFIED_POLICY_ENABLED: "false" # Unified Policy runs as separate service
60+
5161
# OneModel integration (Single-Tenant mode)
5262
JF_ONEMODEL_ENABLED: "true"
5363
JF_ROUTER_MULTITENANT_SERVICES_ONEMODEL_SERVICEURL: http://onemodel:8082
@@ -99,6 +109,80 @@ services:
99109
- postgres
100110
- artifactory
101111

112+
# AppTrust Service
113+
apptrust-service:
114+
image: ${APPTRUST_IMAGE}
115+
container_name: evidence-e2e-apptrust
116+
environment:
117+
# Node configuration
118+
JF_SHARED_NODE_ID: evidence-e2e-node
119+
120+
# Database configuration
121+
JF_SHARED_DATABASE_TYPE: postgresql
122+
JF_SHARED_DATABASE_DRIVER: org.postgresql.Driver
123+
JF_SHARED_DATABASE_URL: jdbc:postgresql://postgres:5432/evidence
124+
JF_SHARED_DATABASE_USERNAME: evidence
125+
JF_SHARED_DATABASE_PASSWORD: password
126+
127+
# Security keys (must match Artifactory)
128+
JF_SHARED_SECURITY_JOINKEY: cc949ef041b726994a225dc20e018f23
129+
JF_SHARED_SECURITY_MASTERKEY: b055e9d06d17a293f1934109d4c4b560
130+
131+
# AppTrust service configuration
132+
JF_APPTRUST_HTTP_PORT: 8052
133+
JF_APPTRUST_LOGGING_APPLICATION_LEVEL: ${APPTRUST_LOG_LEVEL:-INFO}
134+
JF_ROUTER_ENTRYPOINTS_INTERNALPORT: 8046
135+
136+
# License caching for tests
137+
JF_APPTRUST_CACHING_LICENSE_EXPIRATIONSECS: 1
138+
139+
# AppTrust specific configuration
140+
JF_APPTRUST_ENABLED: "true"
141+
JF_APPTRUST_NAVIGATION_ENABLED: "true"
142+
network_mode: service:artifactory
143+
restart: on-failure
144+
depends_on:
145+
- postgres
146+
- artifactory
147+
- evidence-service
148+
149+
# Unified Policy Service
150+
unified-policy-service:
151+
image: ${UNIFIED_POLICY_IMAGE}
152+
container_name: evidence-e2e-unified-policy
153+
environment:
154+
# Node configuration
155+
JF_SHARED_NODE_ID: evidence-e2e-node
156+
157+
# Database configuration
158+
JF_SHARED_DATABASE_TYPE: postgresql
159+
JF_SHARED_DATABASE_DRIVER: org.postgresql.Driver
160+
JF_SHARED_DATABASE_URL: jdbc:postgresql://postgres:5432/evidence
161+
JF_SHARED_DATABASE_USERNAME: evidence
162+
JF_SHARED_DATABASE_PASSWORD: password
163+
164+
# Security keys (must match Artifactory)
165+
JF_SHARED_SECURITY_JOINKEY: cc949ef041b726994a225dc20e018f23
166+
JF_SHARED_SECURITY_MASTERKEY: b055e9d06d17a293f1934109d4c4b560
167+
168+
# Unified Policy service configuration
169+
JF_UNIFIED_POLICY_HTTP_PORT: 8053
170+
JF_UNIFIED_POLICY_LOGGING_APPLICATION_LEVEL: ${UNIFIED_POLICY_LOG_LEVEL:-INFO}
171+
JF_ROUTER_ENTRYPOINTS_INTERNALPORT: 8046
172+
173+
# License caching for tests
174+
JF_UNIFIED_POLICY_CACHING_LICENSE_EXPIRATIONSECS: 1
175+
176+
# Unified Policy specific configuration
177+
JF_UNIFIED_POLICY_ENABLED: "true"
178+
JF_UNIFIED_POLICY_NAVIGATION_ENABLED: "true"
179+
network_mode: service:artifactory
180+
restart: on-failure
181+
depends_on:
182+
- postgres
183+
- artifactory
184+
- apptrust-service
185+
102186
# OneModel Router (Single-Tenant mode - no etcd needed!)
103187
onemodel-router:
104188
image: ${ROUTER_IMAGE}

tests/e2e/tests/e2e_create_suite.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ func (r *EvidenceE2ETestsRunner) RunCreateEvidenceSuite(t *testing.T) {
3333
t.Run("ForReleaseBundle", func(t *testing.T) {
3434
r.RunCreateEvidenceForReleaseBundle(t)
3535
})
36+
t.Run("ForApplicationVersion", func(t *testing.T) {
37+
r.RunCreateEvidenceForApplicationVersion(t)
38+
})
3639
t.Run("WithMarkdown", func(t *testing.T) {
3740
r.RunCreateEvidenceWithMarkdown(t)
3841
})
@@ -542,3 +545,94 @@ func (r *EvidenceE2ETestsRunner) RunCreateEvidenceWithSubjectSha256(t *testing.T
542545

543546
t.Log("=== ✅ Create Evidence with Subject SHA256 Test Completed Successfully! ===")
544547
}
548+
549+
// RunCreateEvidenceForApplicationVersion tests creating evidence for an application version
550+
func (r *EvidenceE2ETestsRunner) RunCreateEvidenceForApplicationVersion(t *testing.T) {
551+
t.Log("=== Create Evidence - Application Version Test ===")
552+
553+
// Verify shared key pair is available
554+
if SharedPrivateKeyPath == "" || SharedPublicKeyPath == "" {
555+
t.Errorf("Shared key pair not initialized. Ensure PrepareTestsData() was called.")
556+
return
557+
}
558+
t.Logf("Using shared key pair: %s (alias: %s)", SharedPrivateKeyPath, SharedKeyAlias)
559+
560+
tempDir := t.TempDir()
561+
projectKey := "test-project"
562+
563+
// Step 1: Create test application
564+
t.Log("Step 1: Creating test application...")
565+
applicationKey, applicationName := utils.CreateTestApplication(t, r.ServicesManager, projectKey)
566+
t.Logf("✓ Application created: %s (%s)", applicationKey, applicationName)
567+
568+
// Register cleanup for application
569+
t.Cleanup(func() {
570+
utils.CleanupTestApplication(t, r.ServicesManager, applicationKey, projectKey)
571+
})
572+
573+
// Step 2: Create test application version
574+
t.Log("Step 2: Creating test application version...")
575+
applicationVersion := utils.CreateTestApplicationVersion(t, r.ServicesManager, r.LifecycleManager, applicationKey, projectKey)
576+
t.Logf("✓ Application version created: %s:%s", applicationKey, applicationVersion)
577+
578+
// Step 3: Promote application version (ensure manifest exists)
579+
t.Log("Step 3: Promoting application version...")
580+
err := utils.PromoteApplicationVersion(t, r.ServicesManager, applicationKey, applicationVersion, projectKey, "production")
581+
require.NoError(t, err, "Failed to promote application version")
582+
t.Logf("✓ Application version promoted: %s:%s", applicationKey, applicationVersion)
583+
584+
// Step 4: Verify application version manifest exists
585+
t.Log("Step 4: Verifying application version manifest...")
586+
exists := utils.ApplicationVersionExists(t, r.ServicesManager, applicationKey, applicationVersion, projectKey)
587+
require.True(t, exists, "Application version manifest should exist")
588+
t.Log("✓ Application version manifest verified")
589+
590+
// Step 5: Create predicate
591+
t.Log("Step 5: Creating predicate...")
592+
predicate := map[string]interface{}{
593+
"buildType": "application-version-test",
594+
"timestamp": time.Now().Unix(),
595+
"environment": "e2e-test",
596+
"applicationKey": applicationKey,
597+
"applicationVersion": applicationVersion,
598+
"projectKey": projectKey,
599+
"description": "Testing evidence creation for application version",
600+
}
601+
predicateBytes, err := json.MarshalIndent(predicate, "", " ")
602+
require.NoError(t, err)
603+
predicatePath := filepath.Join(tempDir, "predicate.json")
604+
err = os.WriteFile(predicatePath, predicateBytes, 0644)
605+
require.NoError(t, err)
606+
t.Log("✓ Predicate created")
607+
608+
// Step 6: Create evidence for application version using shared key
609+
t.Log("Step 6: Creating evidence for application version...")
610+
createOutput := r.EvidenceUserCLI.RunCliCmdWithOutput(t,
611+
"create",
612+
"--predicate", predicatePath,
613+
"--predicate-type", "https://slsa.dev/provenance/v1",
614+
"--application-key", applicationKey,
615+
"--application-version", applicationVersion,
616+
"--key", SharedPrivateKeyPath,
617+
"--key-alias", SharedKeyAlias,
618+
)
619+
t.Logf("Evidence creation output: %s", createOutput)
620+
require.NotContains(t, createOutput, "Error", "Evidence creation should not error")
621+
require.NotContains(t, createOutput, "Failed", "Evidence creation should not fail")
622+
require.NotContains(t, createOutput, "does not exist", "Application version manifest should be found")
623+
t.Log("✓ Evidence created successfully")
624+
625+
// Step 7: Verify evidence using admin token
626+
t.Log("Step 7: Verifying evidence using admin token...")
627+
verifyOutput := r.EvidenceAdminCLI.RunCliCmdWithOutput(t,
628+
"verify",
629+
"--application-key", applicationKey,
630+
"--application-version", applicationVersion,
631+
"--public-keys", SharedPublicKeyPath,
632+
)
633+
t.Logf("Verification output: %s", verifyOutput)
634+
require.Contains(t, verifyOutput, applicationKey, "Evidence should be verified")
635+
t.Log("✅ Evidence verified successfully!")
636+
637+
t.Log("=== ✅ Create Evidence for Application Version Test Completed Successfully! ===")
638+
}

tests/e2e/utils/e2e_apptrustx.go

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package utils
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"testing"
7+
"time"
8+
9+
"github.com/jfrog/jfrog-client-go/artifactory"
10+
"github.com/jfrog/jfrog-client-go/artifactory/services"
11+
"github.com/jfrog/jfrog-client-go/lifecycle"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
// CreateTestApplication creates a test application in AppTrust and returns the application key
16+
func CreateTestApplication(t *testing.T, artifactoryManager artifactory.ArtifactoryServicesManager, projectKey string) (string, string) {
17+
// Generate unique application name with timestamp
18+
timestamp := time.Now().Unix()
19+
applicationKey := fmt.Sprintf("test-app-%d", timestamp)
20+
applicationName := fmt.Sprintf("Test Application %d", timestamp)
21+
22+
t.Logf("Creating test application: %s in project: %s", applicationKey, projectKey)
23+
24+
// Create application using Artifactory REST API
25+
// Note: In a real environment, this would use AppTrust API, but for E2E tests
26+
// we simulate the application creation by creating the necessary repository structure
27+
28+
// Create application-versions repository for the project
29+
repoKey := fmt.Sprintf("%s-application-versions", projectKey)
30+
if projectKey == "" || projectKey == "default" {
31+
repoKey = "application-versions"
32+
}
33+
34+
// Create the repository if it doesn't exist
35+
CreateTestRepository(t, artifactoryManager, "generic", WithRepoKey(repoKey))
36+
37+
t.Logf("✓ Application created: %s (%s)", applicationKey, applicationName)
38+
return applicationKey, applicationName
39+
}
40+
41+
// CreateTestApplicationVersion creates a test application version and returns the version string
42+
func CreateTestApplicationVersion(t *testing.T, artifactoryManager artifactory.ArtifactoryServicesManager, lifecycleManager *lifecycle.LifecycleServicesManager, applicationKey, projectKey string) string {
43+
// Generate unique version with timestamp
44+
timestamp := time.Now().Unix()
45+
version := fmt.Sprintf("1.0.%d", timestamp%10000) // Keep version reasonable
46+
47+
t.Logf("Creating test application version: %s:%s", applicationKey, version)
48+
49+
// Create a release bundle that represents the application version
50+
// This simulates what AppTrust does internally - it creates release bundles for application versions
51+
rbName := applicationKey
52+
rbVersion := version
53+
54+
// Create the release bundle using lifecycle manager
55+
actualRbName, actualRbVersion := CreateTestReleaseBundle(t, artifactoryManager, lifecycleManager, projectKey, WithReleaseBundleName(rbName), WithReleaseBundleVersion(rbVersion))
56+
57+
// Create the application version manifest in the application-versions repository
58+
err := createApplicationVersionManifest(t, artifactoryManager, applicationKey, version, projectKey, actualRbName, actualRbVersion)
59+
require.NoError(t, err, "Failed to create application version manifest")
60+
61+
t.Logf("✓ Application version created: %s:%s", applicationKey, version)
62+
return version
63+
}
64+
65+
// createApplicationVersionManifest creates the release-bundle.json.evd manifest file for an application version
66+
func createApplicationVersionManifest(t *testing.T, artifactoryManager artifactory.ArtifactoryServicesManager, applicationKey, version, projectKey, rbName, rbVersion string) error {
67+
// Build repository key
68+
repoKey := fmt.Sprintf("%s-application-versions", projectKey)
69+
if projectKey == "" || projectKey == "default" {
70+
repoKey = "application-versions"
71+
}
72+
73+
// Create manifest content (simulates what AppTrust creates)
74+
manifest := map[string]interface{}{
75+
"application_key": applicationKey,
76+
"application_version": version,
77+
"project_key": projectKey,
78+
"release_bundle_name": rbName,
79+
"release_bundle_version": rbVersion,
80+
"created_at": time.Now().Format(time.RFC3339),
81+
"type": "application-version",
82+
}
83+
84+
manifestBytes, err := json.MarshalIndent(manifest, "", " ")
85+
if err != nil {
86+
return fmt.Errorf("failed to marshal manifest: %w", err)
87+
}
88+
89+
// Upload manifest to the correct path: {repo}/{app}/{version}/release-bundle.json.evd
90+
manifestPath := fmt.Sprintf("%s/%s/%s/release-bundle.json.evd", repoKey, applicationKey, version)
91+
92+
// Create temporary file for upload
93+
tempFile := CreateTestArtifact(t, string(manifestBytes))
94+
95+
// Upload the manifest
96+
err = UploadArtifact(artifactoryManager, tempFile, manifestPath)
97+
if err != nil {
98+
return fmt.Errorf("failed to upload manifest to %s: %w", manifestPath, err)
99+
}
100+
101+
t.Logf("✓ Application version manifest created at: %s", manifestPath)
102+
return nil
103+
}
104+
105+
// PromoteApplicationVersion simulates promoting an application version (creates the manifest)
106+
func PromoteApplicationVersion(t *testing.T, artifactoryManager artifactory.ArtifactoryServicesManager, applicationKey, version, projectKey, targetStage string) error {
107+
t.Logf("Promoting application version %s:%s to stage: %s", applicationKey, version, targetStage)
108+
109+
// In a real environment, this would call AppTrust promotion API
110+
// For E2E tests, we ensure the manifest exists (it should already be created by CreateTestApplicationVersion)
111+
112+
// Build repository key and manifest path
113+
repoKey := fmt.Sprintf("%s-application-versions", projectKey)
114+
if projectKey == "" || projectKey == "default" {
115+
repoKey = "application-versions"
116+
}
117+
118+
manifestPath := fmt.Sprintf("%s/%s/%s/release-bundle.json.evd", repoKey, applicationKey, version)
119+
120+
// Verify the manifest exists
121+
_, err := artifactoryManager.FileInfo(manifestPath)
122+
if err != nil {
123+
return fmt.Errorf("application version manifest not found at %s: %w", manifestPath, err)
124+
}
125+
126+
t.Logf("✓ Application version %s:%s promoted to %s", applicationKey, version, targetStage)
127+
return nil
128+
}
129+
130+
// CleanupTestApplication removes test application and its versions
131+
func CleanupTestApplication(t *testing.T, artifactoryManager artifactory.ArtifactoryServicesManager, applicationKey, projectKey string) {
132+
// Build repository key
133+
repoKey := fmt.Sprintf("%s-application-versions", projectKey)
134+
if projectKey == "" || projectKey == "default" {
135+
repoKey = "application-versions"
136+
}
137+
138+
// Delete application folder from repository
139+
applicationPath := fmt.Sprintf("%s/%s", repoKey, applicationKey)
140+
141+
// Delete application folder from repository using delete service
142+
deleteParams := services.NewDeleteParams()
143+
deleteParams.Pattern = applicationPath
144+
deleteParams.Recursive = true
145+
146+
pathsToDelete, err := artifactoryManager.GetPathsToDelete(deleteParams)
147+
if err != nil {
148+
t.Logf("Warning: Failed to get paths to delete for application %s: %v", applicationKey, err)
149+
return
150+
}
151+
defer func() {
152+
if err := pathsToDelete.Close(); err != nil {
153+
fmt.Printf("Error closing pathsToDelete: %v\n", err)
154+
}
155+
}()
156+
157+
deletedCount, err := artifactoryManager.DeleteFiles(pathsToDelete)
158+
if err != nil {
159+
t.Logf("Warning: Failed to cleanup application %s: %v", applicationKey, err)
160+
} else {
161+
t.Logf("✓ Cleaned up application: %s (%d items deleted)", applicationKey, deletedCount)
162+
}
163+
}
164+
165+
// ApplicationVersionExists checks if an application version manifest exists
166+
func ApplicationVersionExists(t *testing.T, artifactoryManager artifactory.ArtifactoryServicesManager, applicationKey, version, projectKey string) bool {
167+
// Build repository key and manifest path
168+
repoKey := fmt.Sprintf("%s-application-versions", projectKey)
169+
if projectKey == "" || projectKey == "default" {
170+
repoKey = "application-versions"
171+
}
172+
173+
manifestPath := fmt.Sprintf("%s/%s/%s/release-bundle.json.evd", repoKey, applicationKey, version)
174+
175+
_, err := artifactoryManager.FileInfo(manifestPath)
176+
return err == nil
177+
}

0 commit comments

Comments
 (0)