diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..588e5db0 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,205 @@ +# AI Agent Guide for GP Links Adaptor (NHAIS) + +## Project Overview + +This is a Spring Boot 3.5.6 healthcare integration adaptor that translates between FHIR/JSON REST APIs and EDIFACT EDI messages, acting as a gateway between GP systems and the health authority via MESH (Message Exchange for Social Care and Health). + +**Key Constraint**: Changes must not break the stateful conversation with PCRM/NHAIS systems. MongoDB contains critical sequence numbers and state that synchronize GP and HA systems. + +## Architecture: Three Message Pipelines + +### 1. Outbound (GP → HA via MESH) + +- **REST Entry**: `FhirController` (FHIR Parameters), `AmendmentController` (JSON Patch) +- **Conversion**: `FhirToEdifactService`, `JsonPatchToEdifactService` +- **Stream**: REST → `OutboundQueueService.publishMessage()` → ActiveMQ → `OutboundQueueService.consumeMessage()` → `MeshService.sendMessage()` → MESH +- **State Tracking**: `OutboundState` MongoDB document tracks conversion timestamp, EDIFACT sequences, transaction type (ACG, AMG, REG, DER) +- **Critical**: Sequence numbers in `outboundSequenceId` collection must never be leaked/lost + +### 2. Inbound (HA → GP via MESH) + +- **MESH Poll**: `MeshService.readNextMessage()` runs on distributed lock via `MeshMailBoxScheduler` (MongoDB-backed, prevents duplicate reads) +- **Routing**: `InboundQueueService` listener → `RegistrationConsumerService` OR `RecepConsumerService` +- **Conversion**: `EdifactToFhirService` (approval/rejection/deduction) OR `EdifactToPatchService` (amendments) +- **GP Publishing**: Messages published to `NHAIS_GP_SYSTEM_INBOUND_QUEUE_NAME` with headers: `OperationId`, `TransactionType` +- **RECEP Handling**: Special acknowledgement messages update corresponding `OutboundState` document with receipt confirmation + +### 3. State Management + +- **Idempotency**: Indexed lookups on both `OutboundState` and `InboundState` prevent duplicate processing +- **TTL Expiration**: `NHAIS_MONGO_TTL` (default P30D) auto-removes old documents via MongoDB TTL index +- **Compound Keys**: Sequences tracked as `--` (e.g., `TN-TES5-XX11`) +- **OperationId**: Synthesized from GP Trading Partner + transaction number for matching inbound approvals/rejections + +## Critical Patterns & Conventions + +### Transaction Types (3-char abbreviation codes) + +**Outbound**: ACG (acceptance), AMG (amendment), REG (removal/out-of-area), DER (deduction request) +**Inbound**: APF (approval), REF (rejection), AMF (amendment), DEF (deduction), FPN (FP69 prior notification), FFR (FP69 flag removal), DRR (deduction request rejection), CQN (close quarter notification - acknowledged but not forwarded) + +**Pattern**: Transaction abbreviations are used as identifiers throughout in domain objects, database queries, and MESH workflow IDs. + +### Configuration via Environment Variables + +All configuration is environment-driven (no properties files). Critical ones: +- `NHAIS_MESH_RECIPIENT_MAILBOX_ID_MAPPINGS`: Multi-line mapping of HA codes to MESH mailbox IDs (parsed by custom property parser) +- `NHAIS_MONGO_URI` OR `NHAIS_MONGO_HOST` + `NHAIS_MONGO_PORT`: Choose one pattern +- `NHAIS_AMQP_BROKERS`: Comma-separated list (active/standby, not load-balanced) +- MESH credentials: `NHAIS_MESH_MAILBOX_ID`, `NHAIS_MESH_ENDPOINT_CERT` (PEM format) + +### Testing Structure + +- **Unit/Component Tests**: `@Tag("component")` excluded from `./gradlew test`, run with `./gradlew componentTest` +- **Integration Tests**: Separate source set `src/intTest`, use `@ExtendWith(SpringExtension.class)`, run with `./gradlew integrationTest` +- **Test Data**: Located in `src/intTest/resources/outbound_uat_data/` and `src/intTest/resources/inbound_uat_data/` with triplets: `.fhir.json`, `.edifact.dat`, `.notes.txt` +- **Testcontainers**: Used for integration tests; `TESTCONTAINERS_RYUK_DISABLED=true` env var needed on some workstations (disable only in dev, not CI) +- **No JUnit4**: Codebase uses JUnit5 (`org.junit.jupiter.api.*`); JUnit4 imports will fail +- **E2E Testing NOT AVAILABLE**: OpenTest environment is no longer available. E2E testing against real PCRM/NHAIS systems is not possible. Use local `fake-mesh` for integration testing only. + +### Build Commands (Gradle) + +```bash +./gradlew build # Full build (unit, component, integration tests) +./gradlew test # Unit tests only (component tests excluded) +./gradlew componentTest # Component tests only +./gradlew integrationTest # Integration tests only +./gradlew bootJar # Build application JAR +./gradlew checkstyle # Code style validation +``` + +**CI/CD Pipeline**: Jenkins is no longer used. Build, test, and deployment are handled through GitHub Actions. Do NOT reference Jenkinsfiles as deployment mechanisms. + +### GitHub Actions CI/CD Workflows + +All CI/CD is orchestrated through GitHub Actions workflows in `.github/workflows/`: + +#### 1. **build.yml** (Main Build Pipeline) +Triggered on: PR to `develop` or push to `develop` + +**Workflow**: +1. Runs test workflow (checkstyle, unit tests, component tests, integration tests) +2. Generates unique Build ID using `scripts/create_build_id.sh` (format varies by branch: `PR--` or `develop--`) +3. Builds Docker image and publishes to AWS ECR with Build ID as tag +4. Comments on PR with Build ID for reference + +**Key Outputs**: Build ID tag used for Docker image in ECR; comment added to pull requests with image reference + +#### 2. **test.yml** (Reusable Test Workflow) +Called by build.yml; can be invoked independently + +**Sequential Test Jobs**: +- **checkstyle**: Code style validation via `./gradlew checkStyleMain checkstyleTest checkstyleIntTest` +- **unit-tests** (depends on checkstyle): `./gradlew test --parallel --build-cache` +- **component-tests** (depends on checkstyle): `./gradlew componentTest --build-cache` +- **integration_tests** (depends on checkstyle): Spins up docker-compose (mongodb, activemq, fake-mesh), runs `./gradlew integrationTest`, captures docker logs + +**Artifacts**: Test reports, checkstyle reports, and docker logs uploaded after each job + +**Environment**: Java 21 (Temurin), Gradle with build cache enabled, Docker Compose for integration tests + +#### 3. **publish.yml** (Reusable Docker Publish Workflow) +Called by build.yml after tests pass + +**Steps**: +1. AWS credential assumption via OIDC (uses `AWS_ACCOUNT_ID`, `AWS_ROLE_TO_ASSUME`, `AWS_REGION` secrets) +2. Builds Docker image using provided build-id as tag +3. Logs into AWS ECR +4. Pushes image to `{AWS_ACCOUNT_ID}.dkr.ecr.{AWS_REGION}.amazonaws.com/nhais:{build-id}` +5. Logs out and cleans up credentials + +**Permissions**: `id-token: write` for OIDC, `contents: read` + +#### 4. **release.yml** (Release to DockerHub) +Triggered on: GitHub release published + +**Process**: Delegates to reusable workflow from NHS Digital integration-adaptor-actions repo (`NHSDigital/integration-adaptor-actions/.github/workflows/release-adaptor-container-image.yml`) +- Publishes image to DockerHub as `nia-nhais-adaptor:{release_tag}` +- Attaches release artifacts + +#### 5. **Dependabot Automation** (.github/dependabot.yml) +- **Gradle**: Weekly checks for dependency updates, creates automated PRs +- **GitHub Actions**: Weekly checks for action updates, creates automated PRs + +### Docker & Development + +- **Multi-stage build**: Gradle cache layer, then build layer (Dockerfile line 1-12) +- **Docker Compose**: `docker-compose up mongodb activemq fake-mesh` for local development +- **BUILD_TAG**: Required env var for image versioning; local dev uses `export BUILD_TAG=latest` +- **Fake MESH**: Mock MESH API at `nhsdev/fake-mesh:0.2.0`; development requires `NHAIS_MESH_CERT_VALIDATION=false` +- **Database persistence**: MongoDB should persist between runs in production; dev uses in-memory or ephemeral volumes + +### Deployment Patterns + +- **Stateful**: Adaptor must not be scaled without distributed locking (already implemented via MongoDB) +- **Message Broker**: ActiveMQ (prod), Azure Service Bus, or AmazonMQ supported; requires dead-letter queue configuration +- **AWS DocumentDB**: Supported with custom trust store; optionally auto-enable with `NHAIS_COSMOS_DB_ENABLED=true` +- **Health checks**: Application exposes Spring Boot Actuator (included in starter-actuator) + +## Key Files & Their Responsibilities + +| File/Directory | Purpose | +|---|---| +| `uk.nhs.digital.nhsconnect.nhais.outbound.*` | FHIR/JSON → EDIFACT conversion, REST endpoints | +| `uk.nhs.digital.nhsconnect.nhais.inbound.*` | EDIFACT → FHIR/JSONPatch conversion, queue publishing | +| `uk.nhs.digital.nhsconnect.nhais.mesh.*` | MESH polling, scheduling, HTTP communication | +| `uk.nhs.digital.nhsconnect.nhais.model.*` | Domain objects for EDIFACT segments, FHIR mappings | +| `uk.nhs.digital.nhsconnect.nhais.configuration.*` | Spring config, property binding | +| `src/intTest/resources/outbound_uat_data/` | Test fixtures with real/synthetic transaction examples | +| `INBOUND.md` | Authoritative spec for inbound message headers/formats | +| `README.md` | Configuration reference, local dev setup, troubleshooting | + +## Common Pitfalls & Solutions + +**Sequence Number Resets**: If MongoDB is deleted/cleared, the system loses sync with PCRM. Sequence state is not recoverable without manual HA intervention. + +**Dead Letter Queues**: Undeliverable messages must be manually handled; no automatic recovery. Broker must be strictly configured with redelivery limits and DLQ. + +**MESH Polling Lock**: Only one adaptor instance polls MESH at a time; the lock is held in MongoDB via `MeshMailBoxScheduler`. If lock expires/corrupts during a crash, manually clear the inbound state to recover. + +**Amendment vs Acceptance**: Amendments use EDIFACT UNB segment reuse rules (specific sequences); failures here corrupt the conversation. + +**RECEP Matching**: RECEP messages match outbound transactions via EDIFACT sequence numbers, not OperationId. Updates must be transactional in MongoDB. + +## Deprecated & Unavailable (DO NOT USE) + +- **Jenkins**: Deprecated. Do not reference Jenkinsfiles or propose Jenkins-based pipelines. Modern CI/CD systems are used for deployment. +- **OpenTest Environment**: No longer available. E2E testing against real PCRM/NHAIS systems is not possible. Integration tests must use local `fake-mesh` mock only. +- **OpenTest Deployment**: Do not propose deployment to OpenTest or reference OpenTest configuration files (e.g., `export-env-vars.opentest.example.sh`). + +Respect these constraints when proposing solutions; if OpenTest is required for a solution, the task is not achievable with current infrastructure. + +## Code Quality & Security Requirements + +### Mandatory Pre-Commit Checks + +All code changes MUST pass these checks before submission: + +1. **SpotBugs**: Static analysis for potential bugs. Run with `./gradlew spotbugsMain`. Must have zero high-severity findings on modified code. +2. **Checkstyle**: Code style validation. Run with `./gradlew checkstyle`. All violations must be fixed. +3. **Dependabot**: Dependency vulnerability scanning. GitHub Actions automatically checks all dependencies. Address any flagged CVEs before merging. + +### CI/CD Enforcement + +- SpotBugs and Checkstyle run automatically in GitHub Actions during PR checks (part of test.yml) +- Dependabot creates automated PRs for vulnerable dependencies weekly +- PRs cannot merge if code quality or security checks fail + +## When Modifying Code + +1. **Check if state persists**: Does the change affect sequence numbers, state tracking, or EDIFACT segment generation? If yes, impacts idempotency. +2. **Run code quality checks**: Execute locally: + - `./gradlew checkstyle` (must pass) + - `./gradlew spotbugsMain` (must have no new high-severity findings) + - Review any Dependabot alerts on dependencies you modify +3. **Run full test suite**: `./gradlew check` (not just unit tests) +4. **Test with integrationTest**: Real EDIFACT parsing, MESH communication paths need coverage +5. **Verify configuration**: New env vars must be documented in README.md and added to docker-compose.yml +6. **Preserve backward compatibility**: Old adaptor instances may coexist; breaking serialization of OutboundState/InboundState risks data corruption + + + + + + + diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index eae39bfc..00000000 --- a/Jenkinsfile +++ /dev/null @@ -1,240 +0,0 @@ -String tfProject = "nia" -String tfEnvironment = "build1" // change for ptl, vp goes here -String tfComponent = "nhais" // this defines the application - nhais, mhs, 111 etc - -pipeline { - agent{ - label 'jenkins-workers' - } - - options { - timestamps() - buildDiscarder(logRotator(numToKeepStr: "10")) // keep only last 10 builds - } - - environment { - BUILD_TAG = sh label: 'Generating build tag', returnStdout: true, script: 'python3 pipeline/scripts/tag.py ${GIT_BRANCH} ${BUILD_NUMBER} ${GIT_COMMIT}' - BUILD_TAG_LOWER = sh label: 'Lowercase build tag', returnStdout: true, script: "echo -n ${BUILD_TAG} | tr '[:upper:]' '[:lower:]'" - ENVIRONMENT_ID = "nhais-build" - ECR_REPO_DIR = "nhais" - DOCKER_IMAGE = "${DOCKER_REGISTRY}/${ECR_REPO_DIR}:${BUILD_TAG}" - } - - stages { - stage('Build and Test Locally') { - stages { - stage('Run Tests') { - steps { - script { - sh label: 'Create logs directory', script: 'mkdir -p logs build' - if (sh(label: 'Build nhais', script: 'docker build -t local/nhais-tests:${BUILD_TAG} -f Dockerfile.tests .', returnStatus: true) != 0) {error("Failed to build docker image for tests")} - if (sh(label: 'Running tests', script: 'docker run -v /var/run/docker.sock:/var/run/docker.sock --name nhais-tests local/nhais-tests:${BUILD_TAG} gradle check -i', returnStatus: true) != 0) {error("Some tests failed, check the logs")} - } - } - post { - always { - sh "docker cp nhais-tests:/home/gradle/src/build ." - junit '**/build/test-results/**/*.xml' - step([ - $class : 'JacocoPublisher', - execPattern : '**/build/jacoco/*.exec', - classPattern : '**/build/classes/java', - sourcePattern : 'src/main/java', - exclusionPattern : '**/*Test.class' - ]) - sh "rm -rf build" - } - } - } - stage('Build Docker Images') { - steps { - script { - sh label: 'Running docker build', script: 'docker build -t ${DOCKER_IMAGE} .' - } - } - } - stage('Push image') { - when { - expression { currentBuild.resultIsBetterOrEqualTo('SUCCESS') } - } - steps { - script { - if (ecrLogin(TF_STATE_BUCKET_REGION) != 0 ) { error("Docker login to ECR failed") } - String dockerPushCommand = "docker push ${DOCKER_IMAGE}" - if (sh (label: "Pushing image", script: dockerPushCommand, returnStatus: true) !=0) { error("Docker push image failed") } - } - } - } - } - post { - always { - sh label: 'Copy nhais container logs', script: 'docker-compose logs nhais > logs/nhais.log' - sh label: 'Copy activemq logs', script: 'docker-compose logs activemq > logs/inbound.log' - archiveArtifacts artifacts: 'logs/*.log', fingerprint: true -// sh label: 'Copy nhais container logs', script: 'docker-compose logs nhais > logs/nhais.log' -// sh label: 'Copy dynamo container logs', script: 'docker-compose logs dynamodb-local > logs/outbound.log' -// sh label: 'Copy nhais-tests logs', script: 'docker-compose logs nhais-tests > logs/nhais-tests.log' - sh label: 'Stopping containers', script: 'docker-compose down -v' - } - } - } - stage('Deploy and Integration Test') { - when { - expression { currentBuild.resultIsBetterOrEqualTo('SUCCESS') } - } - options { - lock("${tfProject}-${tfEnvironment}-${tfComponent}") - } - stages { - stage('Deploy using Terraform') { - when { - //Stage disabled until NIAD-2110 is fixed - //expression { currentBuild.resultIsBetterOrEqualTo('SUCCESS') } - expression { false } - } - steps { - script { - String tfCodeBranch = "develop" - String tfCodeRepo = "https://github.com/nhsconnect/integration-adaptors" - String tfRegion = "${TF_STATE_BUCKET_REGION}" - List tfParams = [] - Map tfVariables = ["${tfComponent}_build_id": BUILD_TAG] - dir ("integration-adaptors") { - // Clone repository with terraform - git (branch: tfCodeBranch, url: tfCodeRepo) - dir ("terraform/aws") { - // Run TF Init - if (terraformInit(TF_STATE_BUCKET, tfProject, tfEnvironment, tfComponent, tfRegion) !=0) { error("Terraform init failed")} - - // Run TF Plan - if (terraform('plan', TF_STATE_BUCKET, tfProject, tfEnvironment, tfComponent, tfRegion, tfVariables) !=0 ) { error("Terraform Plan failed")} - - //Run TF Apply - if (terraform('apply', TF_STATE_BUCKET, tfProject, tfEnvironment, tfComponent, tfRegion, tfVariables) !=0 ) { error("Terraform Apply failed")} - } // dir terraform/aws - } // dir integration-adaptors - } //script - } //steps - } //stage - } //stages - } - - - } - post { - always { - sh label: 'Stopping containers', script: 'docker-compose down -v' - sh label: 'Remove all unused images not just dangling ones', script:'docker system prune --force' - sh 'docker image rm -f $(docker images "*/*:*${BUILD_TAG}" -q) $(docker images "*/*/*:*${BUILD_TAG}" -q) || true' - } - } -} - -void runSonarQubeAnalysis() { - sh label: 'Running SonarQube analysis', script: "sonar-scanner -Dsonar.host.url=${SONAR_HOST} -Dsonar.login=${SONAR_TOKEN}" -} - -String tfEnv(String tfEnvRepo="https://github.com/tfutils/tfenv.git", String tfEnvPath="~/.tfenv") { - sh(label: "Get tfenv" , script: "git clone ${tfEnvRepo} ${tfEnvPath}", returnStatus: true) - sh(label: "Install TF", script: "${tfEnvPath}/bin/tfenv install" , returnStatus: true) - return "${tfEnvPath}/bin/terraform" -} - - -int terraformInit(String tfStateBucket, String project, String environment, String component, String region) { - String terraformBinPath = tfEnv() - println("Terraform Init for Environment: ${environment} Component: ${component} in region: ${region} using bucket: ${tfStateBucket}") - String command = "${terraformBinPath} init -backend-config='bucket=${tfStateBucket}' -backend-config='region=${region}' -backend-config='key=${project}-${environment}-${component}.tfstate' -input=false -no-color" - dir("components/${component}") { - return( sh( label: "Terraform Init", script: command, returnStatus: true)) - } // dir -} // int TerraformInit - -int terraform(String action, String tfStateBucket, String project, String environment, String component, String region, Map variables=[:], List parameters=[]) { - println("Running Terraform ${action} in region ${region} with: \n Project: ${project} \n Environment: ${environment} \n Component: ${component}") - variablesMap = variables - variablesMap.put('region',region) - variablesMap.put('project', project) - variablesMap.put('environment', environment) - variablesMap.put('tf_state_bucket',tfStateBucket) - parametersList = parameters - parametersList.add("-no-color") - //parametersList.add("-compact-warnings") /TODO update terraform to have this working - - // Get the secret variables for global - String secretsFile = "etc/secrets.tfvars" - writeVariablesToFile(secretsFile,getAllSecretsForEnvironment(environment,"nia",region)) - String terraformBinPath = tfEnv() - List variableFilesList = [ - "-var-file=../../etc/global.tfvars", - "-var-file=../../etc/${region}_${environment}.tfvars", - "-var-file=../../${secretsFile}" - ] - if (action == "apply"|| action == "destroy") {parametersList.add("-auto-approve")} - List variablesList=variablesMap.collect { key, value -> "-var ${key}=${value}" } - String command = "${terraformBinPath} ${action} ${variableFilesList.join(" ")} ${parametersList.join(" ")} ${variablesList.join(" ")} " - dir("components/${component}") { - return sh(label:"Terraform: "+action, script: command, returnStatus: true) - } // dir -} // int Terraform - -int ecrLogin(String aws_region) { - String dockerLogin = "aws ecr get-login-password --region ${aws_region} | docker login -u AWS --password-stdin \"https://\$(aws sts get-caller-identity --query 'Account' --output text).dkr.ecr.${aws_region}.amazonaws.com\"" - return sh(label: "Logging in with Docker", script: dockerLogin, returnStatus: true) -} - -// Retrieving Secrets from AWS Secrets -String getSecretValue(String secretName, String region) { - String awsCommand = "aws secretsmanager get-secret-value --region ${region} --secret-id ${secretName} --query SecretString --output text" - return sh(script: awsCommand, returnStdout: true).trim() -} - -Map decodeSecretKeyValue(String rawSecret) { - List secretsSplitted = rawSecret.replace("{","").replace("}","").split(",") - Map secretsDecoded = [:] - secretsSplitted.each { - String key = it.split(":")[0].trim().replace("\"","") - Object value = it.split(":")[1] - secretsDecoded.put(key,value) - } - return secretsDecoded -} - -List getSecretsByPrefix(String prefix, String region) { - String awsCommand = "aws secretsmanager list-secrets --region ${region} --query SecretList[].Name --output text" - List awsReturnValue = sh(script: awsCommand, returnStdout: true).split() - return awsReturnValue.findAll { it.startsWith(prefix) } -} - -Map getAllSecretsForEnvironment(String environment, String secretsPrefix, String region) { - List globalSecrets = getSecretsByPrefix("${secretsPrefix}-global",region) - println "global secrets:" + globalSecrets - List environmentSecrets = getSecretsByPrefix("${secretsPrefix}-${environment}",region) - println "env secrets:" + environmentSecrets - Map secretsMerged = [:] - globalSecrets.each { - String rawSecret = getSecretValue(it,region) - if (it.contains("-kvp")) { - secretsMerged << decodeSecretKeyValue(rawSecret) - } else { - secretsMerged.put(it.replace("${secretsPrefix}-global-",""),rawSecret) - } - } - environmentSecrets.each { - String rawSecret = getSecretValue(it,region) - if (it.contains("-kvp")) { - secretsMerged << decodeSecretKeyValue(rawSecret) - } else { - secretsMerged.put(it.replace("${secretsPrefix}-${environment}-",""),rawSecret) - } - } - return secretsMerged -} - -void writeVariablesToFile(String fileName, Map variablesMap) { - List variablesList=variablesMap.collect { key, value -> "${key} = ${value}" } - sh (script: "touch ${fileName} && echo '\n' > ${fileName}") - variablesList.each { - sh (script: "echo '${it}' >> ${fileName}") - } -} diff --git a/Jenkinsfile.fake-mesh b/Jenkinsfile.fake-mesh deleted file mode 100644 index e3d3f57a..00000000 --- a/Jenkinsfile.fake-mesh +++ /dev/null @@ -1,42 +0,0 @@ -pipeline { - agent{ - label 'jenkins-workers' - } - - options { - timestamps() - buildDiscarder(logRotator(numToKeepStr: "10")) // keep only last 10 builds - } - - environment { - DOCKER_IMAGE = "${DOCKER_REGISTRY}/${ECR_REPO_DIR}:${BUILD_TAG}" - FAKE_MESH_ECR_REPO_DIR = "nhais-fake-mesh" - FAKE_MESH_VERSION = "0.2.0" - FAKE_MESH_IMAGE = "${DOCKER_REGISTRY}/${FAKE_MESH_ECR_REPO_DIR}:${FAKE_MESH_VERSION}" - } - - stages { - stage('Deploy fake-mesh to ECR') { - steps { - script { - sh label: "Pulling fake-mesh image", script: "docker pull nhsdev/fake-mesh:0.2.0" - sh label: "Re-tag fake-mesh image", script: "docker image tag nhsdev/fake-mesh:0.2.0 ${FAKE_MESH_IMAGE}" - if (ecrLogin(TF_STATE_BUCKET_REGION) != 0 ) { error("Docker login to ECR failed") } - String dockerPushCommand = "docker push ${FAKE_MESH_IMAGE}" - if (sh (label: "Pushing image", script: dockerPushCommand, returnStatus: true) !=0) { error("Docker push image failed") } - } - } - } - } - post { - always { - sh label: 'Remove all unused images not just dangling ones', script:'docker system prune --force' - sh 'docker image rm -f $(docker images "*/*:*${BUILD_TAG}" -q) $(docker images "*/*/*:*${BUILD_TAG}" -q) || true' - } - } -} - -int ecrLogin(String aws_region) { - String dockerLogin = "aws ecr get-login-password --region ${aws_region} | docker login -u AWS --password-stdin \"https://\$(aws sts get-caller-identity --query 'Account' --output text).dkr.ecr.${aws_region}.amazonaws.com\"" - return sh(label: "Logging in with Docker", script: dockerLogin, returnStatus: true) -} diff --git a/Jenkinsfile.responder b/Jenkinsfile.responder deleted file mode 100644 index 7544cba1..00000000 --- a/Jenkinsfile.responder +++ /dev/null @@ -1,50 +0,0 @@ - pipeline { - agent{ - label 'jenkins-workers' - } - - environment { - BUILD_TAG = sh label: 'Generating build tag', returnStdout: true, script: 'python3 pipeline/scripts/tag.py ${GIT_BRANCH} ${BUILD_NUMBER} ${GIT_COMMIT}' - BUILD_TAG_LOWER = sh label: 'Lowercase build tag', returnStdout: true, script: "echo -n ${BUILD_TAG} | tr '[:upper:]' '[:lower:]'" - ENVIRONMENT_ID = "nhais-build" - ECR_REPO_DIR = "nhais-fake-responder" - DOCKER_IMAGE = "${DOCKER_REGISTRY}/${ECR_REPO_DIR}:${BUILD_TAG}" - } - - stages { - stage('Build Locally') { - stages { - stage('Build Docker Images') { - steps { - script { - sh label: 'Running docker build', script: 'docker build -t ${DOCKER_IMAGE} -f Dockerfile.responder .' - } - } - } - stage('Push image') { - when { - expression { currentBuild.resultIsBetterOrEqualTo('SUCCESS') } - } - steps { - script { - if (ecrLogin(TF_STATE_BUCKET_REGION) != 0 ) { error("Docker login to ECR failed") } - String dockerPushCommand = "docker push ${DOCKER_IMAGE}" - if (sh (label: "Pushing image", script: dockerPushCommand, returnStatus: true) !=0) { error("Docker push image failed") } - } - } - } - } -post { - always { - sh label: 'Remove all unused images not just dangling ones', script:'docker system prune --force' - sh 'docker image rm -f $(docker images "*/*:*${BUILD_TAG}" -q) $(docker images "*/*/*:*${BUILD_TAG}" -q) || true' - } - } - } - } - } - -int ecrLogin(String aws_region) { - String dockerLogin = "aws ecr get-login-password --region ${aws_region} | docker login -u AWS --password-stdin \"https://\$(aws sts get-caller-identity --query 'Account' --output text).dkr.ecr.${aws_region}.amazonaws.com\"" - return sh(label: "Logging in with Docker", script: dockerLogin, returnStatus: true) -} \ No newline at end of file diff --git a/nhais-env-example.yaml b/nhais-env-example.yaml index d2993508..f6622576 100644 --- a/nhais-env-example.yaml +++ b/nhais-env-example.yaml @@ -4,8 +4,8 @@ # All values in this file must be a string. Numerical or boolean (true/false) values must be enclosed in single or double quotes. # NHAIS connection settings -NHAIS_OUTBOUND_SERVER_PORT: "80" -NHAIS_AMQP_BROKERS: localhost:5672 +NHAIS_OUTBOUND_SERVER_PORT: "8080" +NHAIS_AMQP_BROKERS: "amqp://localhost:5672" NHAIS_MESH_OUTBOUND_QUEUE_NAME: 'nhais_mesh_outbound' NHAIS_MONGO_DATABASE_NAME: nhais NHAIS_MONGO_URI: mongodb://localhost:27017 @@ -15,24 +15,12 @@ NHAIS_MONGO_TRUST_STORE_PATH: "s3://nhsd-aws-jks/rds-truststore.jks" #S3 path to NHAIS_MONGO_TRUST_STORE_PASSWORD: "changeit" #password for the custom trust store #MESH client settings -NHAIS_MESH_MAILBOX_ID: #Your MESH mailbox id (sender) can be found in your OpenTest welcome e-mail -NHAIS_MESH_MAILBOX_PASSWORD: #The password for MAILBOX_ID can be found in your OpenTest welcome e-mail -NHAIS_MESH_SHARED_KEY: #Shared key used to generate auth token. Provided by MESH operator (OpenTest, PTL, etc) -NHAIS_MESH_HOST: https://localhost:8829/messageexchange/ #fake-mesh as default, for OpenTest use: https://msg.opentest.hscic.gov.uk/messageexchange/ +NHAIS_MESH_MAILBOX_ID: "mesh_mailbox_id" +NHAIS_MESH_MAILBOX_PASSWORD: "mesh_password" +NHAIS_MESH_SHARED_KEY: "shared_key" +NHAIS_MESH_HOST: "https://localhost:8829/messageexchange/" NHAIS_MESH_CERT_VALIDATION: "false" -NHAIS_MESH_ENDPOINT_CERT: | #The content of the endpoint certificate - -----BEGIN CERTIFICATE----- - #keep 2 spaces indent for whole certificate - -----END CERTIFICATE----- -NHAIS_MESH_ENDPOINT_PRIVATE_KEY: | #The content of the endpoint private key - -----BEGIN RSA PRIVATE KEY----- - #keep 2 spaces indent for whole key - -----END RSA PRIVATE KEY----- -NHAIS_MESH_SUB_CA: | #The content of the Sub CA certificate - -----BEGIN CERTIFICATE----- - #keep 2 spaces indent for whole certificate - -----END CERTIFICATE----- -NHAIS_MESH_RECIPIENT_MAILBOX_ID_MAPPINGS: #recipient codes translation in format cypher=mesh_recipient_code (one per line) +NHAIS_MESH_RECIPIENT_MAILBOX_ID_MAPPINGS: "TES5=recipient_mailbox_id" NHAIS_MESH_POLLING_CYCLE_MINIMUM_INTERVAL_IN_SECONDS: "300" NHAIS_MESH_CLIENT_WAKEUP_INTERVAL_IN_MILLISECONDS: "60000"