Skip to content
Draft
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,15 @@ CouchDb Info (port is defined in .env):

[http://localhost:5984/](http://localhost:5984/)

### Integration tests with Karate

The folder `src/test/java/de.bsi.secvisogram.csaf_cms_backend.integration/` & `src/test/java/de.bsi.secvisogram.csaf_cms_backend.integration/` contains [Karate](https://github.com/karatelabs/karate) test files.

Use `./gradlew integrationTest` to run the tests. CSAF-CMS-Backend and all other components must be up an running with the development setup described above.

Settings (like hostnames, port, user and password) can be changed in the feature-files. `template.feature`-file contains all basic request to build that can be used to assemble futher workflow.


## Contributing

You can find our guidelines here [CONTRIBUTING.md](https://github.com/secvisogram/secvisogram/blob/main/CONTRIBUTING.md)
Expand Down
15 changes: 15 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ dependencies {
//testImplementation 'org.testcontainers:junit-jupiter:1.17.6'
testImplementation 'org.mockito:mockito-inline:5.2.0'

// used for integration tests in de.bsi.secvisogram.csaf_cms_backend.integration.KarateRunner
testImplementation 'com.intuit.karate:karate-junit5:1.4.0'

spotbugsSlf4j 'org.slf4j:slf4j-simple:2.0.7'
spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.12.0'
//spotbugsPlugins 'com.mebigfatguy.sb-contrib:sb-contrib:7.6.0'
Expand All @@ -75,6 +78,18 @@ dependencies {
test {
useJUnitPlatform()
testLogging.showStandardStreams = false
filter {
//exclude all integration tests
excludeTestsMatching "de.bsi.secvisogram.csaf_cms_backend.integration.*"
}
}

tasks.register('integrationTest', Test) {
useJUnitPlatform()
testLogging.showStandardStreams = true
filter {
includeTestsMatching("de.bsi.secvisogram.csaf_cms_backend.integration.*")
}
}

tasks.withType(JavaCompile) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package de.bsi.secvisogram.csaf_cms_backend.integration;

import com.intuit.karate.junit5.Karate;


public class KarateRunner {
@Karate.Test
Karate testExport() {
String[] testCases = new String[] {
"classpath:de/bsi/secvisogram/csaf_cms_backend/integration/export.feature"
};
return Karate.run(testCases);
}

@Karate.Test
Karate testFullWorkflow() {
String[] testCases = new String[] {
"classpath:de/bsi/secvisogram/csaf_cms_backend/integration/fullworkflow.feature"
};
return Karate.run(testCases);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
Feature: Test export of documents

Background:
* def authUrl = 'http://localhost:9000'
* def loginPath = '/realms/csaf/protocol/openid-connect/token'
* def logoutPath = '/realms/csaf/protocol/openid-connect/logout'

* def restUrl = 'http://localhost:8081'
* def apiBase = '/api/v1/advisories'

* def username = 'all'
* def password = 'all'

Scenario: Export all formats and store response in folder ./target/
The first document in the list will be exported in all available
formats.

# Login
Given url 'http://localhost:9000/realms/csaf/protocol/openid-connect/token'
* form field client_id = 'secvisogram'
* form field username = 'all'
* form field password = 'all'
* form field grant_type = 'password'
* form field response_type = 'code'
* form field audience = 'secvisogram'
* form field requested_token_type = 'ID'
When method post
Then status 200
* def accessToken = response.access_token
* def refreshToken = response.refresh_token
* def session = response.session_state

#Get advisory list and store first advisory id
Given url 'http://localhost:8081'
* path apiBase
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
When method get
Then status 200
* def advisoryId = response[0].advisoryId

# Download advisory as JSON
* def format = 'JSON'
Given path apiBase + '/' + advisoryId + '/csaf'
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
* param format = format
When method get
Then status 200
* karate.write(response, 'advisory.json')

# Download advisory as HTML
* def format = 'HTML'
Given path apiBase + '/' + advisoryId + '/csaf'
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
* param format = format
When method get
Then status 200
* karate.write(response, 'advisory.html')

# Download advisory as PDF
* def format = 'PDF'
Given path apiBase + '/' + advisoryId + '/csaf'
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
* param format = format
When method get
Then status 200
* karate.write(response, 'advisory.pdf')

# Download advisory as Markdown
* def format = 'Markdown'
Given path apiBase + '/' + advisoryId + '/csaf'
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
* param format = format
When method get
Then status 200
* karate.write(response, 'advisory.md')

# Logout
Given url 'http://localhost:9000/realms/csaf/protocol/openid-connect/logout'
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/x-www-form-urlencoded'
* form field refresh_token = refreshToken
* form field client_id = 'secvisogram'
When method post
* status 204

Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
Feature: Full workflow

Background:
* url 'http://localhost:8081'
* def apiBase = '/api/v1/advisories'

Scenario: oauth 2 flow
# Login
Given url 'http://localhost:9000/realms/csaf/protocol/openid-connect/token'
* form field client_id = 'secvisogram'
* form field username = 'all'
* form field password = 'all'
* form field grant_type = 'password'
* form field response_type = 'code'
* form field audience = 'secvisogram'
* form field requested_token_type = 'ID'
When method post
Then status 200
* def accessToken = response.access_token
* def refreshToken = response.refresh_token
* def session = response.session_state

########
#Upload
Given url 'http://localhost:8081'
* path apiBase
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
* request read('min.json')
When method post
Then status 201
* def advisoryId = response.id
* def revision = response.revision

########
#Change workflow state to Review
#
# Draft, Review, Approved, RfPublication, Published
* def workflowStatus = 'Review'
Given path apiBase + '/' + advisoryId + '/workflowstate/' + workflowStatus
* param revision = revision
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
When method patch
Then status 200

# Get new revision after workflow state change
Given path apiBase
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
When method get
Then status 200
* def filt = function(x){ return x.advisoryId == advisoryId }
* def items = get response[*]
* def revision = karate.filter(items, filt)[0].revision

########
#Change workflow state to Approved
#
* def workflowStatus = 'Approved'
Given path apiBase + '/' + advisoryId + '/workflowstate/' + workflowStatus
* param revision = revision
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
When method patch
Then status 200
# Get new revision after workflow state change
Given path apiBase
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
When method get
Then status 200
* def filt = function(x){ return x.advisoryId == advisoryId }
* def items = get response[*]
* def revision = karate.filter(items, filt)[0].revision

########
#Change workflow state to RfPublication
#
* def workflowStatus = 'RfPublication'
Given path apiBase + '/' + advisoryId + '/workflowstate/' + workflowStatus
* param revision = revision
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
When method patch
Then status 200
# Get new revision after workflow state change
Given path apiBase
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
When method get
Then status 200
* def filt = function(x){ return x.advisoryId == advisoryId }
* def items = get response[*]
* def revision = karate.filter(items, filt)[0].revision

########
#Change workflow state to Published
#
* def workflowStatus = 'Published'
Given path apiBase + '/' + advisoryId + '/workflowstate/' + workflowStatus
* param revision = revision
# final, interim, draft
* param documentTrackingStatus = 'Final'
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
When method patch
Then status 200

# Get new revision after workflow state change
Given path apiBase
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/json'
When method get
Then status 200
* def filt = function(x){ return x.advisoryId == advisoryId }
* def items = get response[*]
* def revision = karate.filter(items, filt)[0].revision

# Logout
Given url 'http://localhost:9000/realms/csaf/protocol/openid-connect/logout'
* header Authorization = 'Bearer ' + accessToken
* header Content-Type = 'application/x-www-form-urlencoded'
* form field refresh_token = refreshToken
* form field client_id = 'secvisogram'
When method post
* status 204

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"csaf": {
"document": {
"category": "csaf_base",
"csaf_version": "2.0",
"publisher": {
"category": "other",
"name": "Automated test data",
"namespace": "https://www.example.com"
},
"title": "title",
"tracking": {
"current_release_date": "2023-07-12T10:00:00.000Z",
"generator": {
"date": "2023-07-12T07:53:29.378Z",
"engine": {
"name": "Secvisogram",
"version": "2.2.5"
}
},
"id": "document-id",
"initial_release_date": "2023-07-12T10:00:00.000Z",
"revision_history": [
{
"date": "2023-07-12T10:00:00.000Z",
"number": "1.0.0",
"summary": "Initial publication"
}
],
"status": "final",
"version": "1.0.0"
}
}
},
"summary": "-",
"legacyVersion": ""
}

Loading