Skip to content

Commit

Permalink
Commiting changes for v10 pipeline migration (#46)
Browse files Browse the repository at this point in the history
* Commiting changes for v10 pipeline migration

* update package-lock.json

* 1.3.20

* Alterations to storage.test.js

* Changing storage unit tests

* Standard js fixes

---------

Co-authored-by: ffcplatform <ffcplatforms@environment-agency.gov.uk>
  • Loading branch information
Oliver-Lewington-Eviden and ffcplatform authored Feb 24, 2025
1 parent 7f38c31 commit 0f8f6bb
Show file tree
Hide file tree
Showing 22 changed files with 125 additions and 65 deletions.
2 changes: 1 addition & 1 deletion Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
@Library('defra-library@v-9') _
@Library('defra-library@v-10') _

buildNodeJs()
6 changes: 4 additions & 2 deletions app/config/message.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ const schema = Joi.object({
username: Joi.string(),
password: Joi.string(),
useCredentialChain: Joi.bool().default(false),
appInsights: Joi.object()
appInsights: Joi.object(),
managedIdentityClientId: Joi.string().optional()
},
alertSubscription: {
address: Joi.string(),
Expand All @@ -22,7 +23,8 @@ const config = {
username: process.env.MESSAGE_QUEUE_USER,
password: process.env.MESSAGE_QUEUE_PASSWORD,
useCredentialChain: process.env.NODE_ENV === PRODUCTION,
appInsights: process.env.NODE_ENV === PRODUCTION ? require('applicationinsights') : undefined
appInsights: process.env.NODE_ENV === PRODUCTION ? require('applicationinsights') : undefined,
managedIdentityClientId: process.env.AZURE_CLIENT_ID
},
alertSubscription: {
address: process.env.ALERT_SUBSCRIPTION_ADDRESS,
Expand Down
6 changes: 4 additions & 2 deletions app/config/storage-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ const schema = Joi.object({
quarantineFolder: Joi.string().default('quarantine'),
returnFolder: Joi.string().default('return'),
useConnectionStr: Joi.boolean().default(false),
createContainers: Joi.boolean().default(false)
createContainers: Joi.boolean().default(false),
managedIdentityClientId: Joi.string().optional()
})

const config = {
Expand All @@ -21,7 +22,8 @@ const config = {
quarantineFolder: process.env.AZURE_STORAGE_QUARANTINE,
returnFolder: process.env.AZURE_STORAGE_RETURN,
useConnectionStr: process.env.AZURE_STORAGE_USE_CONNECTION_STRING,
createContainers: process.env.AZURE_STORAGE_CREATE_CONTAINERS
createContainers: process.env.AZURE_STORAGE_CREATE_CONTAINERS,
managedIdentityClientId: process.env.AZURE_CLIENT_ID
}

const result = schema.validate(config, {
Expand Down
2 changes: 1 addition & 1 deletion app/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if (config.useConnectionStr) {
blobServiceClient = BlobServiceClient.fromConnectionString(config.connectionStr)
} else {
const uri = `https://${config.storageAccount}.blob.core.windows.net`
blobServiceClient = new BlobServiceClient(uri, new DefaultAzureCredential())
blobServiceClient = new BlobServiceClient(uri, new DefaultAzureCredential({ managedIdentityClientId: config.managedIdentityClientId }))
}

const container = blobServiceClient.getContainerClient(config.container)
Expand Down
1 change: 1 addition & 0 deletions appconfig/common.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
container.alertTopicAddress: queue:ffc-pay-alert
Empty file added appconfig/dev.yaml
Empty file.
Empty file.
Empty file added appconfig/prd.yaml
Empty file.
Empty file added appconfig/pre.yaml
Empty file.
Empty file added appconfig/snd2.yaml
Empty file.
Empty file added appconfig/test.yaml
Empty file.
2 changes: 1 addition & 1 deletion helm/ffc-pay-alerting/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ name: ffc-pay-alerting
version: 1.0.0
dependencies:
- name: ffc-helm-library
version: 4.0.0
version: 4.7.2
repository: https://raw.githubusercontent.com/defra/ffc-helm-repository/master/
5 changes: 0 additions & 5 deletions helm/ffc-pay-alerting/templates/azure-identity-binding.yaml

This file was deleted.

5 changes: 0 additions & 5 deletions helm/ffc-pay-alerting/templates/azure-identity.yaml

This file was deleted.

3 changes: 3 additions & 0 deletions helm/ffc-pay-alerting/templates/service-account.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{{- include "ffc-helm-library.service-account" (list . "ffc-pay-alerting.service-account") -}}
{{- define "ffc-pay-alerting.service-account" -}}
{{- end -}}
2 changes: 1 addition & 1 deletion helm/ffc-pay-alerting/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ container:
azureStorageUseConnectionString: false
azureStorageCreateContainers: false

aadPodIdentity: true
workloadIdentity: true

azureIdentity:
clientID: not-a-real-clientID
Expand Down
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ module.exports = {
'<rootDir>/node_modules/',
'<rootDir>/test-output/',
'<rootDir>/test/',
'<rootDir>/jest.config.js'
'<rootDir>/jest.config.js',
'<rootDir>/app/config'
],
modulePathIgnorePatterns: [
'node_modules'
Expand Down
24 changes: 13 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ffc-pay-alerting",
"version": "1.3.19",
"version": "1.3.20",
"description": "Publish alerts from Payment Hub warnings",
"homepage": "https://github.com/DEFRA/ffc-pay-alerting",
"main": "app/index.js",
Expand All @@ -21,10 +21,10 @@
],
"license": "OGL-UK-3.0",
"dependencies": {
"@azure/identity": "4.3.0",
"@azure/identity": "4.4.1",
"@azure/storage-blob": "12.15.0",
"applicationinsights": "2.9.6",
"ffc-messaging": "2.9.1",
"ffc-messaging": "2.10.1",
"joi": "17.7.1",
"log-timestamp": "0.3.0",
"moment": "2.29.4",
Expand Down
6 changes: 5 additions & 1 deletion provision.azure.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
resources:
identity: pay-alerting
topics:
- name: alert
- name: ffc-pay-alert
role: receiver
subscriptions:
- name: ffc-pay-alerting
2 changes: 1 addition & 1 deletion sonar-project.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
sonar.javascript.exclusions=**/jest.config.js,**/__mocks__/**,**/node_modules/**,**/test/**,**/test-output/**
sonar.javascript.exclusions=**/jest.config.js,**/__mocks__/**,**/node_modules/**,**/test/**,**/test-output/**,**/app/config/**
sonar.javascript.lcov.reportPaths=test-output/lcov.info
sonar.exclusions=/test/**,**/*.test.js,*snyk_report.html,*snyk_report.css
115 changes: 85 additions & 30 deletions test/unit/storage.test.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,98 @@
const { getInboundBlobClient, blobServiceClient } = require('../../app/storage')
const config = require('../../app/config').storageConfig

jest.mock('@azure/storage-blob', () => {
const mBlobServiceClient = {
getContainerClient: jest.fn().mockReturnThis(),
getBlockBlobClient: jest.fn().mockReturnThis(),
upload: jest.fn().mockResolvedValue(true),
createIfNotExists: jest.fn().mockResolvedValue(true)
jest.mock('@azure/storage-blob')
jest.mock('@azure/identity')

describe('storage', () => {
let storage
const mockstorage = {
upload: jest.fn().mockResolvedValue({}),
url: 'test-url'
}
return {
BlobServiceClient: {
fromConnectionString: jest.fn(() => mBlobServiceClient)
},
ContainerClient: jest.fn(() => mBlobServiceClient),
BlockBlobClient: jest.fn(() => mBlobServiceClient)

const mockContainer = {
createIfNotExists: jest.fn(),
getBlockBlobClient: jest.fn().mockReturnValue(mockstorage)
}

const mockStorageConfig = {
useConnectionStr: true,
connectionStr: 'connection-string',
createContainers: true,
storageAccount: 'fakestorageaccount',
managedIdentityClientId: 'fake-client-id',
container: 'test-container',
inboundFolder: 'test-folder'
}

const mockBlobServiceClient = {
getContainerClient: jest.fn().mockReturnValue(mockContainer)
}
})

describe('Azure Blob Storage Module', () => {
beforeEach(() => {
jest.resetModules()
jest.clearAllMocks()

require('@azure/storage-blob').BlobServiceClient.fromConnectionString = jest
.fn()
.mockReturnValue(mockBlobServiceClient)

require('@azure/storage-blob').BlobServiceClient.mockImplementation(() => mockBlobServiceClient)

require('@azure/identity').DefaultAzureCredential.mockImplementation(() => ({}))

jest.mock('../../app/config', () => ({
storageConfig: mockStorageConfig
}))

storage = require('../../app/storage')
})

test('uses connection string when config.useConnectionStr is true', async () => {
expect(require('@azure/storage-blob').BlobServiceClient.fromConnectionString)
.toHaveBeenCalledWith(mockStorageConfig.connectionStr)
})

test('should initialize containers and folders', async () => {
const containerClient = blobServiceClient.getContainerClient(config.container)
await containerClient.createIfNotExists()
expect(containerClient.createIfNotExists).toHaveBeenCalled()
test('uses DefaultAzureCredential when config.useConnectionStr is false', async () => {
jest.resetModules()
mockStorageConfig.useConnectionStr = false

jest.mock('../../app/config', () => ({
storageConfig: mockStorageConfig
}))

storage = require('../../app/storage')

expect(require('@azure/identity').DefaultAzureCredential).toHaveBeenCalledWith({
managedIdentityClientId: 'fake-client-id'
})

expect(require('@azure/storage-blob').BlobServiceClient).toHaveBeenCalledWith(
`https://${mockStorageConfig.storageAccount}.blob.core.windows.net`,
expect.any(Object)
)
})

test('should upload placeholder files to folders', async () => {
const containerClient = blobServiceClient.getContainerClient(config.container)
const blockBlobClient = containerClient.getBlockBlobClient(`${config.inboundFolder}/default.txt`)
await blockBlobClient.upload('Placeholder', 'Placeholder'.length)
expect(blockBlobClient.upload).toHaveBeenCalledWith('Placeholder', 'Placeholder'.length)
test('gets outbound blob client', async () => {
const result = await storage.getInboundBlobClient('test-file.txt')
expect(result.url).toBe('test-url')
expect(mockContainer.getBlockBlobClient).toHaveBeenCalledWith('test-folder/test-file.txt')
})

test('should return the correct blob client for inbound folder', async () => {
const blobClient = await getInboundBlobClient('testfile.txt')
expect(blobClient).toBeDefined()
expect(blobClient.upload).toBeDefined()
describe('when using managed identity', () => {
test('creates blob service client with DefaultAzureCredential', () => {
jest.resetModules()
mockStorageConfig.useConnectionStr = false

jest.mock('../../app/config', () => ({
storageConfig: mockStorageConfig
}))

require('../../app/storage')

expect(require('@azure/storage-blob').BlobServiceClient)
.toHaveBeenCalledWith(
`https://${mockStorageConfig.storageAccount}.blob.core.windows.net`,
expect.any(Object)
)
})
})
})

0 comments on commit 0f8f6bb

Please sign in to comment.