Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve docker functionality #28

Merged
merged 1 commit into from
Apr 23, 2024
Merged
Changes from all 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
improve docker functionality
jchartrand committed Apr 23, 2024
commit 9e1c2d4525702ab965a6c526d69d62e3f312019c
20 changes: 19 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@
**/*.env
**/*.env
.git
.github
.husky
coverage
logs
node_modules
.dockerignore
.editorconfig
.eslintrc.cjs
.gitignore
.lintstagedrc.json
.prettierignore
.prettierrc.js
compose-test.yaml
Dockerfile
README
server-dev-only.cert
server-dev-only.key
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# signing-service Changelog

## 0.3.0 - 2024-04-22
### Changed
- add healthz endpoint for use with docker HEALTHCHECK
- update README
- update .dockerignore
- update Dockerfile with multistage production build
- removed unused status package
- update issuer-core import to instead use issuer-instance from npm
- added CHANGELOG

For previous history, see Git commits.
20 changes: 15 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
FROM node:18-alpine
FROM node:18 as builder
ADD . /app
ENV NODE_ENV=production
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]
EXPOSE 4006
RUN npm install

FROM gcr.io/distroless/nodejs18-debian11
COPY --from=builder /app/node_modules /app/node_modules
COPY --from=builder /app/server.js /app/server.js
COPY --from=builder /app/src /app/src
COPY --from=builder /app/package.json /app/package.json

CMD ["app/server.js"]

EXPOSE 4006

6 changes: 6 additions & 0 deletions Dockerfile.local
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM node:20
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]
EXPOSE 4006
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -60,7 +60,7 @@ You can try this signing-service in about three minutes:
2. From a terminal prompt, run:

```
docker run -dp 4006:4006 digitalcredentials/signing-service:0.2.0
docker run -dp 4006:4006 digitalcredentials/signing-service:0.3.0
```

You can now issue test credentials as explained in the [Sign a Credential](#sign-a-credential) section.
25,085 changes: 7,241 additions & 17,844 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -10,18 +10,18 @@
"lint-fix": "eslint --fix . --ext .js",
"test": "NODE_OPTIONS=--experimental-vm-modules npx c8 mocha --timeout 10000 -r dotenv/config dotenv_config_path=src/test-fixtures/.env.testing src/*.test.js",
"coveralls": "npm run test; c8 report --reporter=text-lcov | coveralls",
"prepare": "husky install"
"prepare": "test -d node_modules/husky && husky install || echo \"husky is not installed\""
},
"dependencies": {
"@digitalcredentials/bnid": "^2.1.2",
"@digitalcredentials/cborld": "^4.3.4",
"@digitalcredentials/ed25519-signature-2020": "^3.0.2",
"@digitalcredentials/ed25519-verification-key-2020": "^4.0.0",
"@digitalcredentials/issuer-core": "github:digitalcredentials/issuer-core",
"@digitalcredentials/issuer-instance": "^1.0.5",
"@digitalcredentials/security-document-loader": "^3.1.0",
"@digitalcredentials/status-list-manager-git": "github:digitalcredentials/status-list-manager-git",
"@digitalcredentials/vc": "^5.0.0",
"@interop/did-web-resolver": "^3.0.1",
"axios": "^1.6.8",
"base32-encode": "^2.0.0",
"cors": "^2.8.5",
"crypto-ld": "^7.0.0",
20 changes: 20 additions & 0 deletions src/app.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import express from 'express'
import cors from 'cors'
import axios from 'axios'
import issue from './issue.js'
import generateSeed from './generate.js'
import accessLogger from './middleware/accessLogger.js'
import errorHandler from './middleware/errorHandler.js'
import errorLogger from './middleware/errorLogger.js'
import invalidPathHandler from './middleware/invalidPathHandler.js'
import SigningException from './SigningException.js'
import { getUnsignedVC } from './test-fixtures/vc.js'
import { TEST_TENANT_NAME } from './config.js'

export async function build() {
var app = express()
@@ -17,6 +20,23 @@ export async function build() {
app.use(express.urlencoded({ extended: false }))
app.use(cors())

app.get('/healthz', async function (req, res) {
try {
const { data } = await axios.post(
`${req.protocol}://${req.headers.host}/instance/${TEST_TENANT_NAME}/credentials/sign`,
getUnsignedVC()
)
if (!data.proof)
throw new SigningException(503, 'signing-service healthz failed')
} catch (e) {
console.log(`exception in healthz: ${e}`)
return res.status(503).json({
error: `signing-service healthz check failed with error: ${e}`
})
}
res.send({ message: 'signing-service server status: ok.' })
})

app.get('/', function (req, res) {
res.send({ message: 'signing-service server status: ok.' })
})
48 changes: 47 additions & 1 deletion src/app.test.js
Original file line number Diff line number Diff line change
@@ -2,7 +2,13 @@ import { driver } from '@digitalcredentials/did-method-key'
import { decodeSecretKeySeed } from '@digitalcredentials/bnid'
import { expect } from 'chai'
import request from 'supertest'
import { resetConfig } from './config.js'
import { clearIssuerInstances } from './issue.js'
import {
resetConfig,
deleteSeed,
TEST_TENANT_NAME,
getTenantSeed
} from './config.js'
import {
ed25519_2020suiteContext,
getCredentialStatus,
@@ -216,4 +222,44 @@ describe('api', () => {
.expect(200)
})
})

describe('/healthz', () => {
it('returns 200 when healthy', async () => {
await request(app)
.get(`/healthz`)
.expect('Content-Type', /json/)
.expect((res) => {
expect(res.body.message).to.contain('ok')
})
.expect(200)
})
})

describe('/healthz fail', () => {
// to force an error with the health check, we remove the
// test issuer instance and it's signing seed

beforeEach(async () => {
// make sure all seeds have been loaded before we remove the test seed
await getTenantSeed(TEST_TENANT_NAME)
deleteSeed(TEST_TENANT_NAME)
clearIssuerInstances()
})

after(async () => {
resetConfig()
})

it('returns 503 when not healthy', async () => {
await request(app)
.get(`/healthz`)
.expect('Content-Type', /json/)
.expect((res) => {
console.log('the body:')
console.log(res.body)
expect(res.body.error).to.contain('error')
})
.expect(503)
})
})
})
9 changes: 7 additions & 2 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ const defaultPort = 4006
const defaultConsoleLogLevel = 'silly'
const defaultLogLevel = 'silly'
const testSeed = 'z1AeiPT496wWmo9BG2QYXeTusgFSZPNG3T9wNeTtjrQ3rCB'
const testTenantName = 'testing'
export const TEST_TENANT_NAME = 'testing'
const randomTenantName = 'random'
let DID_SEEDS = {}

@@ -18,7 +18,7 @@ export function setConfig() {

async function parseTenantSeeds() {
// add in the default test key now, so it can be overridden by env
DID_SEEDS[testTenantName] = {
DID_SEEDS[TEST_TENANT_NAME] = {
didSeed: await decodeSeed(testSeed),
didMethod: 'key'
}
@@ -74,6 +74,11 @@ export function resetConfig() {
DID_SEEDS = {}
}

/* for testing, to allow testing broken calls */
export async function deleteSeed(tenantName) {
delete DID_SEEDS[tenantName]
}

export async function getTenantSeed(tenantName) {
if (!Object.keys(DID_SEEDS).length) {
await parseTenantSeeds()
9 changes: 7 additions & 2 deletions src/issue.js
Original file line number Diff line number Diff line change
@@ -4,16 +4,21 @@ import { CryptoLD } from 'crypto-ld'
import { driver as keyDriver } from '@digitalcredentials/did-method-key'
import { driver as webDriver } from '@interop/did-web-resolver'
import { securityLoader } from '@digitalcredentials/security-document-loader'
import { IssuerInstance } from '@digitalcredentials/issuer-core'
import { IssuerInstance } from '@digitalcredentials/issuer-instance'
import { getTenantSeed } from './config.js'
import SigningException from './SigningException.js'

const ISSUER_INSTANCES = {}
let ISSUER_INSTANCES = {}
const documentLoader = securityLoader().build()

const cryptoLd = new CryptoLD()
cryptoLd.use(Ed25519VerificationKey2020)

/* FOR TESTING */
export const clearIssuerInstances = () => {
ISSUER_INSTANCES = {}
}

const buildIssuerInstance = async (seed, method, url) => {
const didDriver = method === 'web' ? webDriver({ cryptoLd }) : keyDriver()
const { didDocument, methodFor } = await didDriver.generate({