From b273dfd2b69dcabf82f53e655413ddb13e822f1e Mon Sep 17 00:00:00 2001 From: Jonathan Gray Date: Fri, 27 May 2022 13:03:13 +0100 Subject: [PATCH] Test both JWT and NONE auth (#46) * add AUTH_TYPE env * made open api auth conditional * refactor auth location * use test.env * conditional security handlers and auth envs * split auth/noauth tests * nyc coverage * test workflow with matrix * version bump * add matrix to release workflow and fix coverage reporting * remove coverage:jwt * remove merge typo --- .github/workflows/release.yml | 6 ++ .github/workflows/tests.yml | 6 ++ .gitignore | 1 + helm/dscp-api/Chart.yaml | 4 +- helm/dscp-api/values.yaml | 2 +- package-lock.json | 4 +- package.json | 6 +- test/integration/regressions.test.js | 5 +- test/integration/routes.test.js | 110 +++++++++++++++++++++++++-- test/test.env | 3 +- 10 files changed, 128 insertions(+), 19 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 546c5e8..59fa4c6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -129,6 +129,9 @@ jobs: run: npm run lint tests: + strategy: + matrix: + auth: [NONE, JWT] name: Run tests runs-on: ubuntu-latest needs: [preconditions] @@ -159,6 +162,9 @@ jobs: time: '30s' - name: Run tests run: npm run test + env: + AUTH_TYPE: ${{ matrix.auth }} + check-version: name: 'Check version' runs-on: ubuntu-latest diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ecc756a..40a4515 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -122,6 +122,9 @@ jobs: run: npm run lint tests: + strategy: + matrix: + auth: [NONE, JWT] name: Run tests runs-on: ubuntu-latest steps: @@ -151,6 +154,9 @@ jobs: time: '30s' - name: Run tests run: npm run test + env: + AUTH_TYPE: ${{ matrix.auth }} + check-version: name: 'Check version' diff --git a/.gitignore b/.gitignore index 4a142dd..d66320e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ node_modules/ # Test coverage coverage .nyc_output +coverage.json # Logs npm-debug.log* diff --git a/helm/dscp-api/Chart.yaml b/helm/dscp-api/Chart.yaml index 7419964..208255a 100644 --- a/helm/dscp-api/Chart.yaml +++ b/helm/dscp-api/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 name: dscp-api -appVersion: '4.2.0' +appVersion: '4.2.1' description: A Helm chart for dscp-api -version: '4.2.0' +version: '4.2.1' type: application dependencies: - name: dscp-node diff --git a/helm/dscp-api/values.yaml b/helm/dscp-api/values.yaml index 225d2ca..69f38a3 100644 --- a/helm/dscp-api/values.yaml +++ b/helm/dscp-api/values.yaml @@ -29,7 +29,7 @@ replicaCount: 1 image: repository: ghcr.io/digicatapult/dscp-api pullPolicy: IfNotPresent - tag: 'v4.2.0' + tag: 'v4.2.1' dscpNode: enabled: false diff --git a/package-lock.json b/package-lock.json index 401d9df..385f3a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "dscp-api", - "version": "4.2.0", + "version": "4.2.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "dscp-api", - "version": "4.2.0", + "version": "4.2.1", "license": "Apache-2.0", "dependencies": { "@digicatapult/dscp-node": "^3.6.0", diff --git a/package.json b/package.json index 5452db6..7c84212 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dscp-api", - "version": "4.2.0", + "version": "4.2.1", "description": "DSCP API", "repository": { "type": "git", @@ -19,12 +19,14 @@ "main": "./app/index.js", "scripts": { "test": "NODE_ENV=test mocha --config ./test/mocharc.js ./test", + "test:jwt": "NODE_ENV=test AUTH_TYPE=JWT mocha --config ./test/mocharc.js ./test", "test:unit": "NODE_ENV=test mocha --config ./test/mocharc.js ./test/unit", "test:integration": "NODE_ENV=test mocha --config ./test/mocharc.js ./test/integration", "lint": "eslint .", "start": "NODE_ENV=production node app/index.js", "dev": "NODE_ENV=development nodemon app/index.js | pino-colada", - "coverage": "LOG_LEVEL=fatal NODE_ENV=development nyc mocha --recursive ./test/integration --timeout 60000 --slow 20000 --exit" + "coverage": "LOG_LEVEL=fatal NODE_ENV=development nyc mocha --recursive ./test/integration --timeout 60000 --slow 20000 --exit", + "coverage:merge": "LOG_LEVEL=fatal NODE_ENV=development nyc --no-clean npm run test && nyc --no-clean npm run test:jwt && nyc merge .nyc_output --timeout 60000 --slow 20000 --exit" }, "dependencies": { "@digicatapult/dscp-node": "^3.6.0", diff --git a/test/integration/regressions.test.js b/test/integration/regressions.test.js index 043de9b..a9ecfea 100644 --- a/test/integration/regressions.test.js +++ b/test/integration/regressions.test.js @@ -11,11 +11,12 @@ const { createHttpServer } = require('../../app/server') const { getItemRoute, getLastTokenIdRoute } = require('../helper/routeHelper') const USER_ALICE_TOKEN = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY' const { rolesEnum } = require('../../app/util/appUtil') -const { API_MAJOR_VERSION, AUTH_ISSUER, AUTH_AUDIENCE } = require('../../app/env') +const { API_MAJOR_VERSION, AUTH_ISSUER, AUTH_AUDIENCE, AUTH_TYPE } = require('../../app/env') const defaultRole = { [rolesEnum[0]]: USER_ALICE_TOKEN } +const describeAuthOnly = AUTH_TYPE === 'JWT' ? describe : describe.skip -describe('Bug regression tests', function () { +describeAuthOnly('Bug regression tests', function () { describe('API run-process is broken with file uploads (https://github.com/digicatapult/dscp-api/issues/17)', function () { let app let jwksMock diff --git a/test/integration/routes.test.js b/test/integration/routes.test.js index 63c5a10..aaaedb9 100644 --- a/test/integration/routes.test.js +++ b/test/integration/routes.test.js @@ -36,6 +36,7 @@ const { PROCESS_IDENTIFIER_LENGTH, IPFS_HOST, IPFS_PORT, + AUTH_TYPE, } = require('../../app/env') const { responses: healthcheckResponses } = require('../helper/healthcheckFixtures') @@ -46,6 +47,9 @@ const BASE58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' const bs58 = require('base-x')(BASE58) const defaultRole = { [rolesEnum[0]]: USER_ALICE_TOKEN } +const describeAuthOnly = AUTH_TYPE === 'JWT' ? describe : describe.skip +const describeNoAuthOnly = AUTH_TYPE === 'NONE' ? describe : describe.skip + describe('routes', function () { before(async () => { nock.disableNetConnect() @@ -255,7 +259,7 @@ describe('routes', function () { }) }) - describe('access token', async () => { + describeAuthOnly('auth token route', async () => { // Inputs let app, statusHandler const tokenResponse = { @@ -288,7 +292,7 @@ describe('routes', function () { }) }) - describe('invalid credentials', async () => { + describeAuthOnly('auth token route - invalid credentials', async () => { // Inputs let app, statusHandler const deniedResponse = { error: 'Unauthorised' } @@ -311,14 +315,9 @@ describe('routes', function () { expect(res.status).to.equal(401) expect(res.body).to.deep.equal(deniedResponse) }) - - test('invalid token', async function () { - const result = await getLastTokenIdRoute(app, 'invalidToken') - expect(result.status).to.equal(401) - }) }) - describe('authenticated routes', function () { + describeAuthOnly('authenticated', function () { let app let jwksMock let authToken @@ -728,6 +727,11 @@ describe('routes', function () { }) describe('invalid requests', function () { + test('invalid bearer token', async function () { + const result = await getLastTokenIdRoute(app, 'invalidToken') + expect(result.status).to.equal(401) + }) + test('add item - missing FILE attachments', async function () { const outputs = [ { roles: defaultRole, metadata: { testFile1: { type: 'FILE', value: './test/data/test_file_01.txt' } } }, @@ -1181,4 +1185,94 @@ describe('routes', function () { }) }) }) + + describeNoAuthOnly('no auth', function () { + let app + let statusHandler + const process = {} + + before(async function () { + const server = await createHttpServer() + app = server.app + statusHandler = server.statusHandler + }) + + after(function () { + statusHandler.close() + }) + + withNewTestProcess(process) + + describe('happy path', function () { + test('add and get item metadata - FILE + LITERAL + TOKEN_ID + NONE', async function () { + const outputs = [ + { + roles: defaultRole, + metadata: { + testFile: { type: 'FILE', value: './test/data/test_file_01.txt' }, + testLiteral: { type: 'LITERAL', value: 'notAFile' }, + testTokenId: { type: 'TOKEN_ID', value: '42' }, + testNone: { type: 'NONE' }, + }, + }, + ] + const runProcessResult = await postRunProcess(app, null, [], outputs) + expect(runProcessResult.body).to.have.length(1) + expect(runProcessResult.status).to.equal(200) + + const lastToken = await getLastTokenIdRoute(app, null) + expect(lastToken.body).to.have.property('id') + + const getItemResult = await getItemRoute(app, null, lastToken.body) + expect(getItemResult.status).to.equal(200) + expect(getItemResult.body.id).to.equal(lastToken.body.id) + expect(getItemResult.body.metadata_keys).to.deep.equal(['testFile', 'testLiteral', 'testNone', 'testTokenId']) + + const testFile = await getItemMetadataRoute(app, null, { + id: lastToken.body.id, + metadataKey: 'testFile', + }) + expect(testFile.body.toString('utf8')).equal('This is the first test file...\n') + expect(testFile.header['content-disposition']).equal('attachment; filename="test_file_01.txt"') + expect(testFile.header['content-type']).equal('application/octet-stream') + + const testLiteral = await getItemMetadataRoute(app, null, { + id: lastToken.body.id, + metadataKey: 'testLiteral', + }) + + expect(testLiteral.text).equal('notAFile') + expect(testLiteral.header['content-type']).equal('text/plain; charset=utf-8') + + const testTokenId = await getItemMetadataRoute(app, null, { + id: lastToken.body.id, + metadataKey: 'testTokenId', + }) + + expect(testTokenId.text).equal('42') + expect(testTokenId.header['content-type']).equal('text/plain; charset=utf-8') + + const testNone = await getItemMetadataRoute(app, null, { + id: lastToken.body.id, + metadataKey: 'testNone', + }) + + expect(testNone.text).to.equal('') + expect(testNone.header['content-type']).equal('text/plain; charset=utf-8') + }) + + test('return membership members', async function () { + let expectedResult = [ + { address: USER_BOB_TOKEN }, + { address: ALICE_STASH }, + { address: USER_ALICE_TOKEN }, + { address: BOB_STASH }, + ] + + const res = await getMembersRoute(app, null) + + expect(res.body).deep.equal(expectedResult) + }) + }) + }) }) diff --git a/test/test.env b/test/test.env index 9299359..eb74d9c 100644 --- a/test/test.env +++ b/test/test.env @@ -9,5 +9,4 @@ IPFS_PORT=5001 AUTH_TOKEN_URL=https://mock-auth-service AUTH_JWKS_URI=https://mock-auth-service/.well-known/jwks.json AUTH_AUDIENCE=mock-audience -AUTH_ISSUER=https://mock-auth-service -AUTH_TYPE=JWT \ No newline at end of file +AUTH_ISSUER=https://mock-auth-service \ No newline at end of file