From a9b558bfefb40340a496a7a7f1af1ae6dc32fef7 Mon Sep 17 00:00:00 2001 From: James Cruddas Date: Mon, 24 Aug 2026 14:18:30 +0100 Subject: [PATCH] feature: add OSS required documentation files and SPDX header (#50) * IA-139 sonar fixes (#22) * fix: small sonar issues * Add sonar properties file and fix sonar issues * Refactor functions to reduce cognititive complexity * fix: add sonarqube rules, refactor function to fix logic * Update Readme * IA-473 Documentation - contributors (#23) IA-473 Documentation - contributors * chore(deps): bump the python-packages group across 1 directory with 9 updates (#26) * IA-509: Formalise Docs (#29) * IA-509: Formalise Docs * update changelog * Update CONTRIBUTING.md * commit * Update MAINTAINERS.md * Update CHANGELOG.md --------- Co-authored-by: Conaill4 Co-authored-by: Conaill O Neill <85241039+Conaill4@users.noreply.github.com> * IA-524: Add markdown templates for bug report reports, feature requests and pull requests (#32) Co-authored-by: peter.rooke * Update Maintainers file (#35) * Replace MAINTAINERS.md with standard template and update contact details * Update changelog to reflect maintainers file changes --------- Co-authored-by: Joshua Samuel * docs(OSPO): maintainers information update * bugfix(non-req): fixed normalize headers method for kafka sink (#41) * bugfix(non-req): fixed normalize headers method for kafka sink * feat(OSPO): synchronise OSPO workflows * feature(OSPO): add inner-source licensing materials * feat: update maintainer files * fix(headers): add spdx headers to all python files, and update change log * fix: patch GH actions * fix(changelog): update change log * fix: update National Node Net pointer --------- Co-authored-by: JanaL22 <116157760+JanaL22@users.noreply.github.com> Co-authored-by: athomas-kainos Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Harrison Duffield <46687573+HarrisonDuffield@users.noreply.github.com> Co-authored-by: Conaill4 Co-authored-by: Conaill O Neill <85241039+Conaill4@users.noreply.github.com> Co-authored-by: Peter Rooke Co-authored-by: peter.rooke Co-authored-by: JenniKate Wallace Co-authored-by: Joshua Samuel Co-authored-by: KumailKamranIS <131384933+KumailKamranIS@users.noreply.github.com> Co-authored-by: Rotimi Joseph --- .github/ISSUE_TEMPLATE/bug_report.md | 25 +- .github/ISSUE_TEMPLATE/feature_request.md | 1 + ...T_TEMPLATE.md => pull_request_template.md} | 0 .github/workflows/auto-back-merge.yml | 93 --- .github/workflows/oss-checker.yml | 587 +++--------------- .github/workflows/publish-github-release.yml | 59 +- ACKNOWLEDGEMENTS.md | 24 +- CHANGELOG.md | 152 ++--- CODE_OF_CONDUCT.md | 16 +- CONTRIBUTING.md | 10 +- LICENSE | 201 ------ LICENSE.md | 297 ++++++--- MAINTAINERS.md | 92 +-- NOTICE | 4 - NOTICE.md | 20 + OGL_LICENSE.md | 16 + README.md | 45 +- SECURITY.md | 14 +- debug.py | 27 +- ia_map_lib/__init__.py | 23 + ia_map_lib/action.py | 49 +- ia_map_lib/adapter.py | 23 + ia_map_lib/config/__init__.py | 23 + ia_map_lib/config/configSource.py | 23 + ia_map_lib/config/configurator.py | 53 +- ia_map_lib/config/kafka.py | 23 + ia_map_lib/datasets/__init__.py | 23 + ia_map_lib/datasets/datasets.py | 31 +- ia_map_lib/errors.py | 26 +- ia_map_lib/exceptions.py | 23 + ia_map_lib/logging.py | 23 + ia_map_lib/mapper.py | 23 + ia_map_lib/middleware/__init__.py | 23 + ia_map_lib/middleware/decode_token.py | 25 +- ia_map_lib/projector.py | 23 + ia_map_lib/records.py | 39 +- ia_map_lib/reporter.py | 23 + ia_map_lib/sinks/__init__.py | 23 + ia_map_lib/sinks/dataSink.py | 23 + ia_map_lib/sinks/dictSink.py | 23 + ia_map_lib/sinks/kafkaSink.py | 86 ++- ia_map_lib/sinks/listSink.py | 21 + ia_map_lib/sinks/serializers.py | 23 + ia_map_lib/sources/__init__.py | 23 + ia_map_lib/sources/dataSource.py | 23 + ia_map_lib/sources/deserializers.py | 23 + ia_map_lib/sources/dictSource.py | 22 + ia_map_lib/sources/kafkaSource.py | 58 +- ia_map_lib/sources/listSource.py | 22 + ia_map_lib/status.py | 23 + ia_map_lib/utils.py | 26 +- pyproject.toml | 18 +- sonar-project.properties | 26 + tests/__init__.py | 20 + tests/delaySink.py | 23 + tests/test_adapter.py | 23 + tests/test_data/__init__.py | 21 + tests/test_data/utils_test_hosts.py | 23 + tests/test_data_catalogue.py | 23 + tests/test_decode_token_middleware.py | 23 + tests/test_error_handler.py | 23 + tests/test_generate_ids.py | 31 +- tests/test_mapper.py | 23 + tests/test_persistent_security_headers.py | 23 + tests/test_projector.py | 25 +- tests/test_protocol_validation.py | 25 +- tests/test_records.py | 23 + tests/test_reporter.py | 23 + tests/test_serdes.py | 85 +-- tests/test_sinks.py | 23 + tests/test_sources.py | 23 + tests/test_utils.py | 23 + 72 files changed, 1812 insertions(+), 1339 deletions(-) rename .github/{PULL_REQUEST_TEMPLATE.md => pull_request_template.md} (100%) delete mode 100644 .github/workflows/auto-back-merge.yml delete mode 100644 LICENSE delete mode 100644 NOTICE create mode 100644 NOTICE.md create mode 100644 OGL_LICENSE.md create mode 100644 sonar-project.properties diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 3205926..e0a7150 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,4 +1,5 @@ --- + name: Bug report about: Create a report to help us improve title: '' @@ -12,11 +13,9 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: - -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error +1. Run '...' +2. Observe on '....' +3. See error/exception (etc) **Expected behavior** A clear and concise description of what you expected to happen. @@ -24,18 +23,10 @@ A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. -**Desktop (please complete the following information):** - -- OS: [e.g. iOS] -- Browser [e.g. chrome, safari] -- Version [e.g. 22] - -**Smartphone (please complete the following information):** - -- Device: [e.g. iPhone6] -- OS: [e.g. iOS8.1] -- Browser [e.g. stock browser, safari] -- Version [e.g. 22] +**System (please complete the following information):** +- Container [e.g. docker image] +- OS: [e.g. Ubuntu] +- Version [e.g. 20.04.3] **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7..549a887 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,4 +1,5 @@ --- + name: Feature request about: Suggest an idea for this project title: '' diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/pull_request_template.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE.md rename to .github/pull_request_template.md diff --git a/.github/workflows/auto-back-merge.yml b/.github/workflows/auto-back-merge.yml deleted file mode 100644 index 111d548..0000000 --- a/.github/workflows/auto-back-merge.yml +++ /dev/null @@ -1,93 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme and is legally attributed to the Department for Business and Trade (UK) as the governing entity. - -# This workflow is triggered when a pull request is merged into the main branch and automatically merges the main branch back into develop to keep it up to date. -# If the merge fails (e.g., due to conflicts), a manual intervention is required. The workflow generates a Job summary of the merge attempt. -name: Auto Back-merge Main to Develop - -on: - pull_request: - types: - - closed - branches: - - main - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - merge-main-to-develop: - - permissions: {} - - name: Back-merge Main to Develop - if: github.event.pull_request.merged == true - runs-on: ubuntu-latest - - steps: - - - name: Generate Sync Token - id: sync-token - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 - with: - app-id: ${{ secrets.NODE_NET_REPOSITORY_WRITER_APP_CLIENT_ID }} - private-key: ${{ secrets.NODE_NET_REPOSITORY_WRITER_APP_PRIVATE_KEY }} - permission-contents: write - permission-workflows: write - - - name: Merge main into develop and Generate Summary - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ steps.sync-token.outputs.token }} - script: | - const prNumber = context.payload.pull_request.number; - const mergedBy = context.payload.sender.login; - const prUrl = context.payload.pull_request.html_url; - - try { - // Attempt to merge main into develop, use the api to ensure the commit - // is gpg signed. - await github.rest.repos.merge({ - owner: context.repo.owner, - repo: context.repo.repo, - base: 'develop', - head: 'main', - commit_message: `Merge branch 'main' into 'develop' (#${prNumber})` - }); - - let summaryText = - `## Sync Main to Develop ✅ - - Successfully triggered a merge of \`main\` into \`develop\` following the closure of PR #${prNumber}. - - **Original PR Merged by**: @${mergedBy} - - [View Original PR](${prUrl}) - `; - - await core.summary.addRaw(summaryText).write(); - } catch (error) { - const finalErrorMessage = error.message || error; - // Write failure summary - summaryText = - `## Sync Main to Develop ❌ - - Failed to trigger a merge of \`main\` into \`develop\`! This is usually due to a merge conflict. Please resolve it manually by opening a PR from \`main\` to \`develop\`. - - ### Error Details: - - \`\`\`text - ${finalErrorMessage} - \`\`\` - - **Original PR Merged by**: @${mergedBy} - - [View Original PR](${prUrl}) - `; - - await core.summary.addRaw(summaryText).write(); - - // Fail the workflow step - core.setFailed(`Merge failed: ${finalErrorMessage}`); - } diff --git a/.github/workflows/oss-checker.yml b/.github/workflows/oss-checker.yml index dc6e45f..259d29b 100644 --- a/.github/workflows/oss-checker.yml +++ b/.github/workflows/oss-checker.yml @@ -1,30 +1,17 @@ # SPDX-License-Identifier: Apache-2.0 -# © Crown Copyright 2025. This work has been developed by the National Digital Twin Programme and is legally attributed to the Department for Business and Trade (UK) as the governing entity. +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. name: Run OSS check helper on: - pull_request: - types: - - opened - - synchronize - - reopened - - labeled - - unlabeled workflow_dispatch: +permissions: + contents: read + jobs: oss-checks: - permissions: - contents: read - if: github.actor != 'dependabot[bot]' && - (github.event.repository.private == false || - (github.event.repository.private == true && - contains(join(github.event.pull_request.labels.*.name), 'oss-preparation'))) runs-on: ubuntu-latest - outputs: - summary-table: ${{ steps.summarise_results.outputs.summaryTable }} - has-results: ${{ steps.summarise_results.outputs.hasResults }} steps: - name: Fetch GitHub App token for target repo @@ -46,519 +33,95 @@ jobs: permission-contents: read - name: Checkout target repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: token: ${{ steps.target_token.outputs.token }} - name: Checkout OSPO source repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: National-Node-Net/ospo-resources path: ospo-resources token: ${{ steps.ospo_token.outputs.token }} - name: Checkout archetypes source repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: National-Node-Net/archetypes path: archetypes - - name: Fetch Repository Metadata - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - with: - script: | - const { owner, repo } = context.repo; - const { writeFileSync } = require('fs'); - - // Check specifically for 'develop' branch existence - let hasDevelopBranch = false; - try { - await github.rest.repos.getBranch({ - owner, - repo, - branch: 'develop', - }); - hasDevelopBranch = true; - } catch (error) { - if (error.status !== 404) { - core.warning(`Error checking for develop branch: ${error.message}`); - } - } - - const metadata = { - repository: { - defaultBranch: process.env.DEFAULT_BRANCH, - hasDevelopBranch: hasDevelopBranch - } - }; - - const rawMetadata = JSON.stringify(metadata, null, 2); - - core.info('Content for repository-metadata.json:'); - core.info(rawMetadata); - - writeFileSync('repository-metadata.json', rawMetadata); - core.info('Generated repository-metadata.json for policy context.'); - - - name: Install Conftest - env: - FALLBACK_VERSION: '0.67.1' + - name: Test for presence of OSS files and variation from templated content run: | - set -euo pipefail - - install_conftest() { - local version="$1" - local file_name="conftest_${version}_Linux_x86_64.deb" - curl --proto "=https" --fail -sSL "https://github.com/open-policy-agent/conftest/releases/download/v${version}/${file_name}" -o "${file_name}" - sudo dpkg -i "${file_name}" - rm -f "${file_name}" - } + missing_files=() + unchanged_files=() + + while IFS= read -r file || [ -n "$file" ]; do + # Skip comments and empty lines + if [[ -z "$file" || "$file" == \#* ]]; then + continue + fi + + target_path="$file" + archetypes_path="archetypes/$file" + + if [ ! -f "$target_path" ]; then + echo "Missing OSS file in target repository: $target_path" + missing_files+=("$file") + elif cmp -s "$target_path" "$archetypes_path"; then + echo "OSS file unchanged from archetypes template: $target_path" + unchanged_files+=("$file") + else + echo "OSS file present and different from the archetypes template: $target_path" + fi + done < ospo-resources/oss-checklist-files.txt + + echo "" + if [ ${#missing_files[@]} -ne 0 ]; then + echo "The following OSS required files are missing:" + printf '%s\n' "${missing_files[@]}" + fi - LATEST_VERSION="$(curl --proto "=https" --fail -s "https://api.github.com/repos/open-policy-agent/conftest/releases/latest" | grep -Po '"tag_name": "v\K[0-9.]+' || true)" + if [ ${#unchanged_files[@]} -ne 0 ]; then + echo "The following OSS required files are unchanged from the archetypes template:" + printf '%s\n' "${unchanged_files[@]}" + fi - if [[ -n "${LATEST_VERSION}" ]] && install_conftest "${LATEST_VERSION}"; then - echo "Installed latest Conftest version: ${LATEST_VERSION}" + if [ ${#missing_files[@]} -ne 0 ] || [ ${#unchanged_files[@]} -ne 0 ]; then + echo "OSS required file check failed." + exit 1 else - echo "Failed to install latest Conftest. Falling back to version ${FALLBACK_VERSION}." - install_conftest "${FALLBACK_VERSION}" + echo "All OSS files are present and have been updated from their original templated content." fi - - name: Run Policy Checks - id: run_conftest - run: | - conftest test .github/dependabot.yml \ - -p ospo-resources/tools/policy-as-code/policy \ - --data repository-metadata.json \ - --namespace github.dependabot \ - --output json > policy-report.json || true - - - name: Process Policy Results - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - script: | - const { existsSync, readFileSync, writeFileSync } = require('fs'); - - let resultJson = []; - if (existsSync('policy-report.json')) { - try { - const rawContent = readFileSync('policy-report.json', 'utf8'); - if (rawContent.trim()) { - resultJson = JSON.parse(rawContent); - } - } catch(e) { - core.error(`Failed to parse policy-report.json: ${e.message}`); - core.setFailed(`Failed to parse policy-report.json: ${e.message}`); - return; - } - } - - const results = resultJson.map(r => { - const failureReasons = (r.failures || []).map(f => f.msg); - return { - path: r.filename, - status: failureReasons.length > 0 ? 'failed' : 'passed', - failureReasons: failureReasons, - checks: { - namespace: r.namespace, - successes: r.successes - } - }; - }); - - const passed = results.filter((result) => result.status === 'passed').length; - const failed = results.length - passed; - const score = results.length > 0 ? Number((passed / results.length).toFixed(2)) : 0; - - const prHead = context.payload.pull_request?.head; - const repoFullName = prHead?.repo?.full_name ?? process.env.GITHUB_REPOSITORY ?? 'unknown/unknown'; - const commitSha = prHead?.sha ?? process.env.GITHUB_SHA ?? 'unknown'; - - const report = { - runMetadata: { - timestamp: new Date().toISOString(), - repo: repoFullName, - commit: commitSha, - checkType: 'policy', - }, - files: results, - summary: { - total: results.length, - passed, - failed, - score, - }, - }; - - const reportPath = 'policy-results.json'; - writeFileSync(reportPath, JSON.stringify(report, null, 2)); - core.info(`Wrote policy summary to ${reportPath}`); - - if (failed > 0) { - core.setFailed('Policy checks failed for one or more files.'); - } else { - core.info('All policy checks passed.'); - } - - - name: Test for presence of OSS files and variation from templated content - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - if: success() || failure() - with: - script: | - const { existsSync, readFileSync, writeFileSync } = require('fs'); - - const checklistPath = 'ospo-resources/oss-checklist-files.txt'; - const checklist = readFileSync(checklistPath, 'utf8') - .split('\n') - .map((line) => line.trim()) - .filter((line) => line && !line.startsWith('#')); - - const results = []; - const prHead = context.payload.pull_request?.head; - const repoFullName = prHead?.repo?.full_name ?? process.env.GITHUB_REPOSITORY ?? 'unknown/unknown'; - const commitSha = prHead?.sha ?? process.env.GITHUB_SHA ?? 'unknown'; - - for (const relativePath of checklist) { - const record = { - path: relativePath, - status: 'passed', - checks: { - exists: false, - differsFromTemplate: null, - }, - failureReasons: [], - }; - - const targetPath = relativePath; - const archetypePath = `archetypes/${relativePath}`; - - const fileExists = existsSync(targetPath); - record.checks.exists = fileExists; - - if (!fileExists) { - record.status = 'failed'; - record.failureReasons.push('missing or misnamed'); - core.info(`Missing or misnamed OSS file in target repository: ${targetPath}`); - results.push(record); - continue; - } - - const targetContent = readFileSync(targetPath, 'utf8'); - - if (existsSync(archetypePath)) { - const archetypeContent = readFileSync(archetypePath, 'utf8'); - const differsFromTemplate = targetContent !== archetypeContent; - record.checks.differsFromTemplate = differsFromTemplate; - - if (!differsFromTemplate) { - record.failureReasons.push('unchanged from archetype template'); - core.info(`OSS file unchanged from archetypes template: ${targetPath}`); - } else { - core.info(`OSS file present and different from the archetypes template: ${targetPath}`); - } - } else { - record.checks.differsFromTemplate = null; - core.info(`Template file missing for ${relativePath}; skipping template comparison.`); - } - - record.status = record.failureReasons.length > 0 ? 'failed' : 'passed'; - results.push(record); - } - - const passed = results.filter((result) => result.status === 'passed').length; - const failed = results.length - passed; - const score = results.length > 0 ? Number((passed / results.length).toFixed(2)) : 0; - - const report = { - runMetadata: { - checklistFile: checklistPath, - timestamp: new Date().toISOString(), - repo: repoFullName, - commit: commitSha, - checkType: 'OSS', - }, - files: results, - summary: { - total: results.length, - passed, - failed, - score, - }, - }; - - const reportPath = 'oss-results.json'; - writeFileSync(reportPath, JSON.stringify(report, null, 2)); - core.info(`Wrote checklist summary to ${reportPath}`); - - if (failed > 0) { - const failedFiles = results - .filter((result) => result.status === 'failed') - .map((result) => result.path); - core.setFailed(`The following files failed checks:\n${failedFiles.join('\n')}`); - } else { - core.info('All OSS files are present and have been updated from their original templated content.'); - } - - name: Check GitHub template files are present - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - if: success() || failure() - with: - script: | - const { existsSync, writeFileSync } = require('fs'); - - core.info('Checking for pull request and issue template files'); - - const filesToCheck = [ - '.github/PULL_REQUEST_TEMPLATE.md', - '.github/ISSUE_TEMPLATE/bug_report.md', - '.github/ISSUE_TEMPLATE/feature_request.md', - ]; - - const results = filesToCheck.map((filePath) => { - const exists = existsSync(filePath); - return { - path: filePath, - status: exists ? 'passed' : 'failed', - checks: { - exists, - differsFromTemplate: null, - }, - failureReasons: exists ? [] : ['missing or misnamed'], - }; - }); - - const passed = results.filter((result) => result.status === 'passed').length; - const failed = results.length - passed; - const score = results.length > 0 ? Number((passed / results.length).toFixed(2)) : 0; - - const prHead = context.payload.pull_request?.head; - const report = { - runMetadata: { - timestamp: new Date().toISOString(), - repo: prHead?.repo?.full_name ?? process.env.GITHUB_REPOSITORY ?? 'unknown/unknown', - commit: prHead?.sha ?? process.env.GITHUB_SHA ?? 'unknown', - checkType: 'template', - }, - files: results, - summary: { - total: results.length, - passed, - failed, - score, - }, - }; - - const reportPath = 'template-results.json'; - writeFileSync(reportPath, JSON.stringify(report, null, 2)); - core.info(`Wrote template checklist summary to ${reportPath}`); - - if (failed > 0) { - const missingTemplates = results - .filter((result) => result.status === 'failed') - .map((result) => result.path); - - core.info(''); - core.info('Required GitHub template files were not found or did not match expected casing:'); - missingTemplates.forEach((file) => core.info(` - ${file}`)); - core.info(''); - core.info('These files help improve project collaboration and are considered best practice.'); - core.info('These need to be included in repository contents to improve the developer and repository consumer experience.'); - core.setFailed('Missing or misnamed GitHub template files.'); - } else { - core.info('Required pull request and issue template files present.'); - } - - - name: Generate summary - id: summarise_results - if: always() - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - script: | - const { existsSync, readFileSync } = require('fs'); - - const reportFiles = [ - 'oss-results.json', - 'template-results.json', - 'policy-results.json', - ]; - - const reports = reportFiles - .filter((reportPath) => { - const present = existsSync(reportPath); - if (!present) { - core.info(`Summary step skipping missing report: ${reportPath}`); - } - return present; - }) - .map((reportPath) => JSON.parse(readFileSync(reportPath, 'utf8'))); - - if (reports.length === 0) { - core.info('No report files found; skipping combined summary.'); - core.setOutput('hasResults', 'false'); - return; - } - - const allResults = reports.flatMap((report) => - report.files.map((file) => ({ - ...file, - category: report.runMetadata?.checkType ?? 'unknown', - repo: report.runMetadata?.repo ?? process.env.GITHUB_REPOSITORY ?? 'unknown/unknown', - commit: report.runMetadata?.commit ?? process.env.GITHUB_SHA ?? 'unknown', - })), - ); - - const combinedTableMarkdown = [ - '| 📄 File | ✅ Result | 🧾 Details |', - '| :--- | :---: | :--- |', - ...allResults.map((result) => { - const href = `https://github.com/${result.repo}/blob/${result.commit}/${result.path}`; - const details = result.failureReasons.length > 0 - ? result.failureReasons.join('; ') - : 'Compliant'; - const statusLabel = result.status === 'passed' ? '🟢 Pass' : '🔴 Fail'; - return `| [${result.path}](${href}) | ${statusLabel} | ${details} |`; - }), - ].join('\n'); - - const total = allResults.length; - const passed = allResults.filter((result) => result.status === 'passed').length; - const failed = total - passed; - const score = total > 0 ? (passed / total) * 100 : 0; - const summary = { total, passed, failed, score }; - - const overallStatus = summary.failed === 0 - ? '🎉 Overall status: PASS (all files compliant).' - : '⚠️ Overall status: FAIL (see table below for details).'; - - const summaryMarkdown = [ - '| 📊 Total Files | 🟢 Passed | 🔴 Failed | 🧮 Score |', - '| ---: | ---: | ---: | ---: |', - `| ${summary.total} | ${summary.passed} | ${summary.failed} | ${summary.score.toFixed(0)}% |` - ].join('\n'); - - const prHead = context.payload.pull_request?.head; - const repoFullName = prHead?.repo?.full_name ?? process.env.GITHUB_REPOSITORY ?? 'unknown/unknown'; - const fullSha = prHead?.sha ?? process.env.GITHUB_SHA ?? ''; - const shortSha = fullSha?.slice(0, 7) ?? 'unknown'; - const commitUrl = fullSha - ? `https://github.com/${repoFullName}/commit/${fullSha}` - : null; - const commitLine = commitUrl - ? `Results from commit [\`${shortSha}\`](${commitUrl}).` - : `Results from commit \`${shortSha}\`.`; - - await core.summary - .addRaw('# OSS Check Results ⚙️\n', true) - .addRaw(`\n${combinedTableMarkdown}\n`, true) - .addRaw('\n# Summary 🏁\n', true) - .addRaw(`\n${overallStatus}\n`, true) - .addRaw(`\n${summaryMarkdown}\n`, true) - .addRaw(`\n${commitLine}\n`, true) - .write(); - - core.setOutput('hasResults', 'true'); - core.setOutput('summaryTable', summaryMarkdown); - - if (summary.failed > 0) { - core.setFailed('OSS checks detected one or more failing files.'); - } - - - name: Upload OSS result artifacts - if: ${{ steps.summarise_results.outputs.hasResults == 'true' }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: oss-checks-${{ github.run_id }} - retention-days: 30 - path: | - oss-results.json - template-results.json - policy-results.json - - comment-on-results: - needs: oss-checks - if: >- - always() && - github.event_name == 'pull_request' && - needs.oss-checks.outputs.has-results == 'true' - runs-on: ubuntu-latest - - permissions: - contents: read - pull-requests: write - - steps: - - name: Comment with OSS summary - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - SUMMARY_TABLE: ${{ needs.oss-checks.outputs.summary-table }} - JOB_RESULT: ${{ needs.oss-checks.result }} - with: - script: | - const { owner, repo } = context.repo; - const prNumber = context.payload.pull_request?.number; - - if (!prNumber) { - core.info('No pull request context; skipping comment step.'); - return; - } - - const jobSummaryUrl = `https://github.com/${owner}/${repo}/actions/runs/${context.runId}`; - const prHead = context.payload.pull_request?.head; - const headCommitSha = prHead?.sha ?? process.env.GITHUB_SHA ?? ''; - const shortSha = headCommitSha ? headCommitSha.slice(0, 7) : 'unknown'; - const runResult = process.env.JOB_RESULT?.toLowerCase() ?? ''; - const isFailure = runResult === 'failure'; - - const marker = ''; - const heading = isFailure - ? '## ⚠️ OSS Checks Failed' - : '## ✅ OSS Checks Passed'; - const narration = isFailure - ? 'One or more OSS checks failed in this run.' - : 'All tracked OSS checks passed in this run.'; - - const bodySections = [ - heading, - narration, - process.env.SUMMARY_TABLE, - `Results from commit ${shortSha}, view the full [job summary↗️](${jobSummaryUrl}) for detailed results.` - ]; - - const existingComments = await github.paginate( - github.rest.issues.listComments, - { - owner, - repo, - issue_number: prNumber, - per_page: 100, - }, - ); - - const previous = existingComments.find((comment) => - comment.body?.includes(marker), - ); - - if(previous) { - bodySections.push(':recycle: This comment has been updated with latest results.'); - } - - const body = `${marker}\n${bodySections.join('\n\n')}\n${marker}`; - - if (previous) { - core.info(`Updating existing OSS summary comment (${previous.id}).`); - await github.rest.issues.updateComment({ - owner, - repo, - comment_id: previous.id, - body, - }); - } else { - core.info('Creating new OSS summary comment.'); - await github.rest.issues.createComment({ - owner, - repo, - issue_number: prNumber, - body, - }); - } + run: | + echo "Checking for pull request and issue template files" + + missing_templates=() + + files_to_check=( + ".github/PULL_REQUEST_TEMPLATE.md" + ".github/ISSUE_TEMPLATE/bug_report.md" + ".github/ISSUE_TEMPLATE/feature_request.md" + ) + + for file in "${files_to_check[@]}"; do + if [ ! -f "$file" ]; then + missing_templates+=("$file") + fi + done + + if [ ${#missing_templates[@]} -ne 0 ]; then + echo "" + echo "Required GitHub template files not found:" + printf ' - %s\n' "${missing_templates[@]}" + echo "" + echo "These files help improve project collaboration and are considered best practice." + echo "These need to be included in repository contents to improve the developer and repository consumer experience." + + # Fail the job + echo "Missing required GitHub template files." + exit 1 + else + echo "Required pull request and issue template files present." + fi diff --git a/.github/workflows/publish-github-release.yml b/.github/workflows/publish-github-release.yml index 3f32ba1..ea27e40 100644 --- a/.github/workflows/publish-github-release.yml +++ b/.github/workflows/publish-github-release.yml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: Apache-2.0 -# © Crown Copyright 2025. This work has been developed by the National Digital Twin Programme and is legally attributed to the Department for Business and Trade (UK) as the governing entity. +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. # This workflow is triggered when a pull request is merged into the main branch -# from a release/* or hotfix/* branch. It extracts the release version from the source branch, +# from a release/* branch. It extracts the release version from the source branch, # generates a Software Bill of Materials (SBOM) using the GitHub API, # creates a Git tag with the version, and publishes a GitHub release including the SBOM file. @@ -15,18 +15,12 @@ on: branches: - main -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true +permissions: + contents: write jobs: versioning: - if: | - github.event.pull_request.merged == true && - (startsWith(github.head_ref, 'release/') || startsWith(github.head_ref, 'hotfix/')) - permissions: - contents: read - + if: github.event.pull_request.merged == true && startsWith(github.head_ref, 'release/') name: Extract Release Version runs-on: ubuntu-latest outputs: @@ -34,10 +28,8 @@ jobs: steps: - name: Extract Version from Source Branch Name id: extract_version - env: - HEAD_REF: ${{ github.head_ref }} run: | - SOURCE_BRANCH="$HEAD_REF" + SOURCE_BRANCH="${{ github.head_ref }}" VERSION=$(echo "$SOURCE_BRANCH" | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+') if [ -z "$VERSION" ]; then @@ -49,43 +41,32 @@ jobs: echo "VERSION=$VERSION" >> $GITHUB_OUTPUT - name: Validate Version Format (Semantic Versioning) - env: - VERSION: ${{ env.VERSION }} run: | - if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Error: Invalid version format found. Expected semantic version in release or hotfix branch name (e.g., release/0.9.0 or hotfix/0.9.1)" + if [[ ! "${{ env.VERSION }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Error: Invalid version format found. Expected semantic version in release branch name (e.g., release/0.9.0)" exit 1 fi - name: Print Tag Version - id: print_tag - env: - EXTRACTED_VERSION: ${{ steps.extract_version.outputs.version }} run: | - echo "Identified release semantic version: $EXTRACTED_VERSION" + echo "Identified release semantic version: ${{ steps.extract_version.outputs.version }}" generate-sbom: - permissions: - contents: read - name: Generate SPDX SBOM runs-on: ubuntu-latest needs: [versioning] steps: - name: Checkout Code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Generate SPDX SBOM - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - REPO: ${{ github.repository }} run: | # Call GitHub API to generate SBOM api_response=$(curl -sSL \ -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ -H "X-GitHub-Api-Version: 2022-11-28" \ - "$GITHUB_API_URL/repos/$REPO/dependency-graph/sbom") + "$GITHUB_API_URL/repos/${{ github.repository }}/dependency-graph/sbom") # Extract nested "sbom" object into a valid SPDX file echo "$api_response" | jq '.sbom' > sbom.spdx.json @@ -97,15 +78,12 @@ jobs: path: sbom.spdx.json create-git-tag: - permissions: - contents: write - name: Create Git Tag needs: [versioning, generate-sbom] runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 @@ -115,16 +93,8 @@ jobs: tag: "v${{ needs.versioning.outputs.version }}" message: "Release v${{ needs.versioning.outputs.version }}" force_push_tag: true - # Tag the HEAD commit from the merged release branch not the merge commit to - # ensure the tag points to the correct source code state for the release. - # This ensures that the release tag is also visible on any branch which does - # not contain the merge commit such as develop. - commit_sha: ${{ github.event.pull_request.head.sha }} create-git-release: - permissions: - contents: write - name: Create GitHub Release needs: [versioning, generate-sbom, create-git-tag] runs-on: ubuntu-latest @@ -135,7 +105,7 @@ jobs: name: sbom - name: Create GitHub Release - uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1 + uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 with: tag_name: "v${{ needs.versioning.outputs.version }}" name: "Release v${{ needs.versioning.outputs.version }}" @@ -144,3 +114,4 @@ jobs: prerelease: false files: | sbom.spdx.json + diff --git a/ACKNOWLEDGEMENTS.md b/ACKNOWLEDGEMENTS.md index 14f269c..e4816ab 100644 --- a/ACKNOWLEDGEMENTS.md +++ b/ACKNOWLEDGEMENTS.md @@ -2,6 +2,7 @@ **Repository:** `node-lib` **Description:** `Recognises suppliers, partner organisations, and other contributors to the repository's development.` +**SPDX-License-Identifier:** `OGL-UK-3.0` The National Digital Twin Programme (NDTP) would like to acknowledge the contributions of various organisations and individuals who have supported the development of this repository. @@ -9,32 +10,21 @@ The National Digital Twin Programme (NDTP) would like to acknowledge the contrib Over time, the following organisations have provided technical expertise, development support, and domain knowledge that have contributed to the evolution of this project: -i.e. -- [Supplier A] -- [Supplier B] -- [Supplier C] -- [Supplier D] -(etc.) - - +- [Kainos](https://www.kainos.com/) +- [Telicent](https://telicent.io/) We are grateful for the collaboration that has helped shape this repository. ## Individual contributions -For a list of individual contributors who have made direct commits to this repository, see GitHub’s auto-generated contributor insights: [Contributors](https://github.com/National-Node-Net/node-lib/graphs/contributors). +For a list of individual contributors who have made direct commits to this repository, see GitHub’s auto-generated contributor insights: [Contributors](../../../graphs/contributors). --- **Note:** This acknowledgment does not confer any legal rights, ownership, or imply ongoing involvement by any of the named organisations or individuals. All contributions are made in accordance with the repository’s licensing terms. -© Crown Copyright 2025. This work has been developed by the National Digital Twin Programme and is legally attributed to the Department for Business and Trade (UK) as the governing entity. - -Licensed under the NDTP InnerSource Licence – Version 1.0. +© Crown Copyright 2026. This work has been developed by the National Digital Twin Programme and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. -For full licensing terms, see [LICENSE.md](LICENSE.md). +Licensed under the Open Government Licence v3.0. +For full licensing terms, see [OGL_LICENCE.md](OGL_LICENCE.md). diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e791ff..2eb09c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,135 +1,67 @@ -# Changelog +# Changelog -Licensed under the NDTP InnerSource Licence – Version 1.0. For full licensing terms, see [LICENSE.md](LICENSE.md). +**Repository:** `node-lib` +**Description:** `Tracks all notable changes, version history, and roadmap toward 1.0.0 following Semantic Versioning.` +**SPDX-License-Identifier:** `OGL-UK-3.0` -## [3.1.2] - 2026-07-16 +All notable changes to this repository will be documented in this file. -### Changed +This project follows **Semantic Versioning (SemVer)** ([semver.org](https://semver.org/)), using the format: -- Alignment of GitHub actions to new organisation. +`[MAJOR].[MINOR].[PATCH]` +- **MAJOR** (`X.0.0`) – Incompatible API/feature changes that break backward compatibility. +- **MINOR** (`0.X.0`) – Backward-compatible new features, enhancements, or functionality changes. +- **PATCH** (`0.0.X`) – Backward-compatible bug fixes, security updates, or minor corrections. +- **Pre-release versions** – Use suffixes such as `-alpha`, `-beta`, `-rc.1` (e.g., `2.1.0-beta.1`). +- **Build metadata** – If needed, use `+build` (e.g., `2.1.0+20250314`). -## [3.1.1](https://github.com/telicent-oss/telicent-lib/compare/v3.1.0...v3.1.1) (2024-10-28) +--- +## [0.90.0] 2026-08-24 -### Bug Fixes +### Initial Features -* **kafka-source:** prevent clashing groupids when one not provided ([#55](https://github.com/telicent-oss/telicent-lib/issues/55)) ([675dbe7](https://github.com/telicent-oss/telicent-lib/commit/675dbe7d74bab3381afde629a7bd33670188f370)) +- Key functionality (in Python) for validation and transformation of data in a data pipeline for data ingestion by a secure-agent-graph instance. +- Added SPDX headers. -## [3.1.0](https://github.com/telicent-oss/telicent-lib/compare/v3.0.1...v3.1.0) (2024-10-22) +## Future Roadmap to `1.0.0` +The `0.90.x` series is part of NDTP’s **pre-stable development cycle**, meaning: +- **Minor versions (`0.91.0`, `0.92.0`...) introduce features and improvements** leading to a stable `1.0.0`. +- **Patch versions (`0.90.1`, `0.90.2`...) contain only bug fixes and security updates**. +- **Backward compatibility is NOT guaranteed until `1.0.0`**, though NDTP aims to minimise breaking changes. -### Features +Once `1.0.0` is reached, future versions will follow **strict SemVer rules**. -* file based config for Kafka ([#53](https://github.com/telicent-oss/telicent-lib/issues/53)) ([1a26dc7](https://github.com/telicent-oss/telicent-lib/commit/1a26dc7df450a116035d2e04f26b6f6eb87f3901)) +--- -## [3.0.1](https://github.com/telicent-oss/telicent-lib/compare/v3.0.0...v3.0.1) (2024-09-25) +## Versioning Policy +1. **MAJOR updates (`X.0.0`)** – Typically introduce breaking changes that require users to modify their code or configurations. +- **Breaking changes (default rule)**: Any backward-incompatible modifications require a major version bump. +- **Non-breaking major updates (exceptional cases)**: A major version may also be incremented if the update represents a significant milestone, such as a shift in governance, a long-term stability commitment, or substantial new functionality that redefines the project’s scope. +2. **MINOR updates (`0.X.0`)** – New functionality that is backward-compatible. +3. **PATCH updates (`0.0.X`)** – Bug fixes, performance improvements, or security patches. +4. **Dependency updates** – A **major dependency upgrade** that introduces breaking changes should trigger a **MAJOR** version bump (once at `1.0.0`). -### Bug Fixes +--- -* headers being set on data catalog messages ([#48](https://github.com/telicent-oss/telicent-lib/issues/48)) ([e4f2199](https://github.com/telicent-oss/telicent-lib/commit/e4f2199a9edcd556b9612b8422a87682656a9bab)) +## How to Update This Changelog -## [3.0.0](https://github.com/telicent-oss/telicent-lib/compare/v2.2.1...v3.0.0) (2024-09-19) +1. When making changes, update this file under the **Unreleased** section. +2. Before a new release, move changes from **Unreleased** to a new dated section with a version number. +3. Follow **Semantic Versioning** rules to categorise changes correctly. +4. If pre-release versions are used, clearly mark them as `-alpha`, `-beta`, or `-rc.X`. +--- -### ⚠ BREAKING CHANGES +**Maintained by the National Digital Twin Programme (NDTP).** -* Dataset objects used to provide additional meta data about a dataset to adapters ([#46](https://github.com/telicent-oss/telicent-lib/issues/46)) +© Crown Copyright 2026. This work has been developed by the National Digital Twin Programme and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. -### Features +Licensed under the Open Government Licence v3.0. -* Dataset objects used to provide additional meta data about a dataset to adapters ([#46](https://github.com/telicent-oss/telicent-lib/issues/46)) ([d6817cd](https://github.com/telicent-oss/telicent-lib/commit/d6817cd791cfb02f9bd3458924b44c3c3113799d)) +For full licensing terms, see [OGL_LICENCE.md](OGL_LICENCE.md). -## [2.2.1](https://github.com/telicent-oss/telicent-lib/compare/v2.2.0...v2.2.1) (2024-09-04) - -### Bug Fixes - -* changed catalogue to catalog and updated dc default topic ([#44](https://github.com/telicent-oss/telicent-lib/issues/44)) ([c8825b3](https://github.com/telicent-oss/telicent-lib/commit/c8825b3d502a778f4d2729fc0e95e41b15ccd4e6)) - -## [2.2.0](https://github.com/telicent-oss/telicent-lib/compare/v2.1.0...v2.2.0) (2024-09-03) - - -### Features - -* data source update notifications can be sent to a specified sink ([#41](https://github.com/telicent-oss/telicent-lib/issues/41)) ([d7987fb](https://github.com/telicent-oss/telicent-lib/commit/d7987fba9393bbc8ae6fe730a87cef5da9e24fb2)) -* security labels from input record persisted to output record in mappers ([#42](https://github.com/telicent-oss/telicent-lib/issues/42)) ([98cc604](https://github.com/telicent-oss/telicent-lib/commit/98cc604613ddbeb115ed4ce8b5d4c8b800dd2c24)) - -## [2.1.0](https://github.com/telicent-oss/telicent-lib/compare/v2.0.7...v2.1.0) (2024-08-15) - - -### Features - -* added source headers ([#36](https://github.com/telicent-oss/telicent-lib/issues/36)) ([1f0c60f](https://github.com/telicent-oss/telicent-lib/commit/1f0c60f5cb45848668ca1469d81f4390118a91d3)) - -## [2.0.7](https://github.com/telicent-oss/telicent-lib/compare/v2.0.6...v2.0.7) (2024-08-14) - - -### Bug Fixes - -* allow full install on Python 3.9 ([#38](https://github.com/telicent-oss/telicent-lib/issues/38)) ([f176f56](https://github.com/telicent-oss/telicent-lib/commit/f176f56618ce0af7b7775a77b599885ba92801a8)) - -## [2.0.6](https://github.com/telicent-oss/telicent-lib/compare/v2.0.5...v2.0.6) (2024-08-14) - - -### Miscellaneous - -* limited support for python 3.9 ([#35](https://github.com/telicent-oss/telicent-lib/issues/35)) ([0868e99](https://github.com/telicent-oss/telicent-lib/commit/0868e99efacf41452fc6b0e7874a7b4c91580299)) - -## [2.0.5](https://github.com/telicent-oss/telicent-lib/compare/v2.0.4...v2.0.5) (2024-07-09) - - -### Bug Fixes - -* handled topic not found exception ([#29](https://github.com/telicent-oss/telicent-lib/issues/29)) ([55b7a84](https://github.com/telicent-oss/telicent-lib/commit/55b7a848785fa4a24cd420ada397d55fd860a317)) - - -### Miscellaneous - -* pr scanning and updated ruff checks to py310 ([#28](https://github.com/telicent-oss/telicent-lib/issues/28)) ([0c88188](https://github.com/telicent-oss/telicent-lib/commit/0c88188a6593309a9ddb627e3cab4b943efa950f)) -* update requests dependency add urllib3 to override older version provided by types-requests ([#34](https://github.com/telicent-oss/telicent-lib/issues/34)) ([c5bbb25](https://github.com/telicent-oss/telicent-lib/commit/c5bbb25f0948bdefbf38e94a8771341444e5743c)) - -## [2.0.4](https://github.com/telicent-oss/telicent-lib/compare/v2.0.3...v2.0.4) (2024-06-27) - - -### Miscellaneous - -* add types-pytz and types-python-dateutil to pre-commit config ([6f91762](https://github.com/telicent-oss/telicent-lib/commit/6f9176294b0ba2a96bc6ca540d061d6904f914fd)) -* Remove SecurityLabels funtionality - now a dependency ([#27](https://github.com/telicent-oss/telicent-lib/issues/27)) ([1924284](https://github.com/telicent-oss/telicent-lib/commit/19242843fa723b8262a0b7708a9a43ca4f5f5e63)) -* update repository url in pyproject ([2b534c2](https://github.com/telicent-oss/telicent-lib/commit/2b534c200a75542ab0c6094dc4a02e40f515dc58)) - -## [2.0.3](https://github.com/telicent-oss/telicent-lib/compare/v2.0.2...v2.0.3) (2024-05-31) - - -### Miscellaneous - -* changed to PEP 604 annotations ([#20](https://github.com/telicent-oss/telicent-lib/issues/20)) ([07c7afe](https://github.com/telicent-oss/telicent-lib/commit/07c7afe9d0f3cd6af3e18cde6751af6766772dd4)) -* switched to builtin types ([#25](https://github.com/telicent-oss/telicent-lib/issues/25)) ([8858dbc](https://github.com/telicent-oss/telicent-lib/commit/8858dbca8b634e9bcbdb4f955cdc2c0ed7b5fa68)) - -## [2.0.2](https://github.com/telicent-oss/telicent-lib/compare/v2.0.1...v2.0.2) (2024-05-22) - - -### Bug Fixes - -* moved jira-mapping-rules yaml ([#13](https://github.com/telicent-oss/telicent-lib/issues/13)) ([eb2c9d4](https://github.com/telicent-oss/telicent-lib/commit/eb2c9d42d4da521b0b72cbd5b78ccb77b24c485a)) -* updated werkzeug to 3.0.3 ([#17](https://github.com/telicent-oss/telicent-lib/issues/17)) ([a281a2c](https://github.com/telicent-oss/telicent-lib/commit/a281a2c8ef1429f89254c966ee4e81321dc4dfcd)) - - -### Miscellaneous - -* **configurator:** used logger rather than print statements ([#10](https://github.com/telicent-oss/telicent-lib/issues/10)) ([b33eb8e](https://github.com/telicent-oss/telicent-lib/commit/b33eb8e24589f14e8750b8e380bcc08dc413586e)) - -## [2.0.1](https://github.com/telicent-oss/telicent-lib/compare/v2.0.0...v2.0.1) (2024-05-09) - - -### Bug Fixes - -* projector and adapter reporter text, and decode token logger init ([#8](https://github.com/telicent-oss/telicent-lib/issues/8)) ([7f46762](https://github.com/telicent-oss/telicent-lib/commit/7f46762a57fb834f7366d2912af5c76d1fce27e0)) - -## 2.0.0 (2024-05-01) - - -### Features - -* initial release ([c605ee7](https://github.com/telicent-oss/telicent-lib/commit/c605ee76a5dea86585112620b4350855d527ccc5)) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 00be292..6746325 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,10 +2,11 @@ **Repository:** `node-lib` **Description:** `Defines expected behaviors, rules, and the enforcement process to ensure professional engagement.` +**SPDX-License-Identifier:** `OGL-UK-3.0` ## Introduction -The National Digital Twin Programme (NDTP) is committed to fostering an open, inclusive, and professional environment in all its repositories. +The National Digital Twin Programme (NDTP) is committed to fostering an open, inclusive, and professional environment in all its public repositories. This Code of Conduct outlines the expectations for behaviour when engaging with NDTP repositories, including issue reporting, documentation feedback, and discussions with repository maintainers. @@ -40,10 +41,8 @@ The following behaviour will not be tolerated: If you believe someone is violating this Code of Conduct, please report it by following these steps: -1. **For general issues** – Raise a concern with the repository maintainers by emailing ndtp@businessandtrade.gov.uk. - -2. **For security-related concerns** – Follow the responsible disclosure process outlined in [SECURITY.md](./SECURITY.md). - +1. **For general issues** – Raise a concern with the repository maintainers by emailing [NDTP Support Email]. +2. **For security-related concerns** – Follow the responsible disclosure process outlined in [SECURITY.md] (./SECURITY.md). 3. **For incidents requiring escalation** – NDTP reserves the right to take appropriate action, including restricting access to contributors who violate this policy. All reports will be reviewed confidentially, and NDTP will take appropriate action to address the issue. @@ -75,9 +74,8 @@ This Code of Conduct applies to all interactions in NDTP repositories, including **Maintained by the National Digital Twin Programme (NDTP).** -© Crown Copyright 2025. This work has been developed by the National Digital Twin Programme and is legally attributed to the Department for Business and Trade (UK) as the governing entity. - -Licensed under the NDTP InnerSource Licence – Version 1.0. +© Crown Copyright 2026. This work has been developed by the National Digital Twin Programme and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. -For full licensing terms, see [LICENSE.md](LICENSE.md). +Licensed under the Open Government Licence v3.0. +For full licensing terms, see [OGL_LICENCE.md](OGL_LICENCE.md). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d1f054a..49a4065 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,6 +2,7 @@ **Repository:** `node-lib` **Description:** `Guidelines for issue reporting, documentation suggestions, and NDTP’s controlled contribution model.` +**SPDX-License-Identifier:** `OGL-UK-3.0` Thank you for your interest in this repository. @@ -9,7 +10,7 @@ The National Digital Twin Programme (NDTP) develops and maintains this repositor NDTP follows a **Cathedral open-source governance model** where code may be made **publicly available** under open-source licences, and collaboration is invited from **approved partners**. Contributions from the general public are not currently accepted, but **feedback, issue reporting, and documentation suggestions are encouraged**. -If you want to see which suppliers and organisations have contributed to this repository in the past, refer to [ACKNOWLEDGEMENTS.md](./ACKNOWLEDGEMENTS.md) and the GitHub contributor insights page at [Contributors](https://github.com/National-Node-Net/node-lib/graphs/contributors). +If you want to see which suppliers and organisations have contributed to this repository in the past, refer to [ACKNOWLEDGEMENTS.md](./ACKNOWLEDGEMENTS.md) and the GitHub contributor insights page at [Contributors](../../graphs/contributors). --- @@ -115,9 +116,8 @@ NDTP repository maintainers review reported issues, evaluate documentation sugge **Maintained by the National Digital Twin Programme (NDTP).** -© Crown Copyright 2025. This work has been developed by the National Digital Twin Programme and is legally attributed to the Department for Business and Trade (UK) as the governing entity. +© Crown Copyright 2026. This work has been developed by the National Digital Twin Programme and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. -Licensed under the NDTP InnerSource Licence – Version 1.0. - -For full licensing terms, see [LICENSE.md](LICENSE.md). +Licensed under the Open Government Licence v3.0. +For full licensing terms, see [OGL_LICENCE.md](./OGL_LICENCE.md) diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 6b1eaa3..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2024 TELICENT LTD - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/LICENSE.md b/LICENSE.md index 7120b21..a9ffa93 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,96 +1,213 @@ -# NDTP InnerSource License +# License -**Repository:** `node-lib` -**Description:** `Defines the licensing terms for the source code in this repository.` +## Copyright Notice +© Crown Copyright 2026. This work has been developed by the National Digital Twin Programme and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. ---- - -## Version - -**NDTP InnerSource License – Version 1.0** -**Issued by:** National Digital Twin Programme (NDTP) -**Effective Date:** 9 July 2025 - ---- - -## Copyright - -© Crown Copyright 2025. -This work has been developed by the **National Digital Twin Programme (NDTP)** and is legally attributed to the **Department for Business and Trade (UK)** as the governing entity. - -This repository is **not open source**. -Its contents are licensed under the terms of this **NDTP InnerSource License**, unless and until it is formally published under an approved open source licence by the NDTP Management Team. - ---- - -## 1. Purpose - -This repository supports InnerSource development practices within the NDTP. It enables collaborative development by internal teams and authorised suppliers, in a controlled and non-public environment. - ---- - -## 2. Licensing Status - -This work is **not licensed under an open source licence**. -It must not be published, distributed, sublicensed, or shared externally without the **explicit, written approval** of the NDTP Management Team. - -> The NDTP InnerSource Licence permits internal collaboration only. No part of this repository may be used or disclosed beyond the authorised delivery context. - ---- - -## 3. Intellectual Property - -All rights, including intellectual property rights in this code and associated materials, are owned by the NDTP. - -Where contributions are made by suppliers or delivery partners, those contributions are accepted on the basis that **full intellectual property rights** belong to the Crown under the terms of their contract. - ---- - -## 4. Permitted Use - -You may: - -- View, use, and modify the code as required to fulfil your responsibilities under the NDTP. -- Collaborate within authorised NDTP teams and with approved suppliers under existing contracts. - -You may not: - -- Share, publish, or release this repository publicly. -- Fork, clone, or redistribute this code outside approved NDTP channels. -- Apply any license other than the NDTP InnerSource License to this repository or its contents, unless instructed by the NDTP Management Team. - ---- - -## 5. Future Publication - -At the discretion of the NDTP Management Team, this repository may later be designated for release under an approved open source licence. - -Any such designation must follow NDTP's internal governance processes. - -> Until such designation is explicitly made and executed, this repository remains **confidential and proprietary**. - ---- - -## 6. Enforcement - -Any unauthorised disclosure, publication, or redistribution of this repository or its contents may: - -- Constitute a breach of contract -- Trigger formal investigation -- Result in legal, disciplinary, or commercial action, including revocation of access rights - -All actions will be escalated to the NDTP Management Team for appropriate handling. - ---- - -## Contact - -For all enquiries regarding licensing, publication status, or contributor rights, please contact: +This work is licensed under the Apache License, Version 2.0. -**NDTP Management Team** -Department for Business and Trade (UK) -NDTP@BUSINESSANDTRADE.GOV.UK +**Note:** All documentation in this repository is licensed under the Open Government Licence v3.0 (OGL-3.0). See [OGL_LICENSE.md](OGL_LICENSE.md) for full terms. --- -**End of NDTP InnerSource Licence – Version 1.0** + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2025 Crown Copyright, National Digital Twin Programme, + legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/MAINTAINERS.md b/MAINTAINERS.md index c38b3b7..28239b8 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -2,75 +2,7 @@ **Repository:** `node-lib` **Description:** `Lists maintainers responsible for reviewing issues, security, and documentation updates.` - -## Introduction - -This repository is maintained by the **National Digital Twin Programme (NDTP)** in collaboration with contracted suppliers and partner organisations. - -Maintainers are responsible for reviewing issues, evaluating documentation suggestions, and overseeing -supplier-led development. - -If you need to report a problem, suggest improvements, or seek guidance on using this repository, please refer to the contacts listed below. - ---- - -## Responsibilities of Maintainers - -Maintainers are responsible for: - -- Reviewing and responding to **GitHub Issues**. -- Assessing **documentation updates and corrections**. -- Overseeing **code updates** developed by NDTP-approved suppliers. -- Ensuring compliance with **NDTP’s licensing and security policies**. - -NDTP does not accept public code contributions, but we welcome **bug reports and documentation feedback**. - ---- - -## Current Maintainers - -| Name | Organisation | Role | Contact | -|-------------------|------------------------|--------------------|------------------------| -| [Maintainer Name] | [NDTP / Supplier Name] | Lead Maintainer | [email@example.org] | -| [Maintainer Name] | [NDTP / Supplier Name] | Security Contact | [security@example.org] | -| [Maintainer Name] | [NDTP / Supplier Name] | Documentation Lead | [docs@example.org] | - -For general issues, please **open a GitHub issue** rather than contacting maintainers directly. - ---- - -## Escalation Contacts - -If you need to escalate an issue that has not been addressed within a reasonable time: - -1. **Security vulnerabilities** – Follow the responsible disclosure process in [SECURITY.md](./SECURITY.md). -2. **Governance and policy queries** – Contact NDTP at **ndtp@businessandtrade.gov.uk**. -3. **Urgent operational issues** – If an issue affects critical systems, contact the **Lead Maintainer** listed above. - ---- - -## Updating this File - -Maintainer details may change over time. If you are an NDTP-approved maintainer and need to update this file, please submit a request through the designated NDTP repository administrator. - ---- - -**Maintained by the National Digital Twin Programme (NDTP).** - -© Crown Copyright 2025. This work has been developed by the National Digital Twin Programme and is legally attributed to the Department for Business and Trade (UK) as the governing entity. - -Licensed under the NDTP InnerSource Licence – Version 1.0. - -For full licensing terms, see [LICENSE.md](LICENSE.md). - - +For full licensing terms, see [OGL_LICENCE.md](./OGL_LICENCE.md) diff --git a/NOTICE b/NOTICE deleted file mode 100644 index ebdeb83..0000000 --- a/NOTICE +++ /dev/null @@ -1,4 +0,0 @@ -telicent-lib -============ - -Copyright (c) 2024 Telicent Ltd. \ No newline at end of file diff --git a/NOTICE.md b/NOTICE.md new file mode 100644 index 0000000..3e1e863 --- /dev/null +++ b/NOTICE.md @@ -0,0 +1,20 @@ +# NOTICE + +**Repository:** `node-lib` +**Description:** `Attribution and legal notices related to the use of this repository, including acknowledgments of external contributions.` +**SPDX-License-Identifier:** `OGL-UK-3.0` + +This repository contains software developed as part of the National Digital Twin Programme (NDTP), a UK Government initiative. + +© Crown Copyright 2026. This work has been developed by the National Digital Twin Programme and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + +## License +This repository contains **both source code and documentation**, each covered by different licenses: +- **Code**: Licensed under the **[Apache License 2.0](./LICENSE.md)**. +- **Documentation**: Licensed under the **[Open Government Licence v3.0 (OGL-UK-3.0)](./OGL_LICENCE.md)**. + +See [`LICENSE.md`](LICENSE.md) and [`OGL_LICENCE.md`](OGL_LICENCE.md) for details. + +This project has been developed to support NDTP’s mission of enabling secure, scalable, and interoperable data-sharing across organisations. + +For a list of acknowledgments, see [ACKNOWLEDGEMENTS.md](./ACKNOWLEDGEMENTS.md). \ No newline at end of file diff --git a/OGL_LICENSE.md b/OGL_LICENSE.md new file mode 100644 index 0000000..a6339ed --- /dev/null +++ b/OGL_LICENSE.md @@ -0,0 +1,16 @@ +# Open Government Licence v3.0 + +**Repository:** `node-lib` +**Description:** `Covers all documentation files in this repository that are released under the Open Government Licence v3.0.` +**SPDX-License-Identifier:** `OGL-UK-3.0` + +This repository contains documentation licensed under the Open Government Licence (OGL) v3.0. +You are encouraged to use and re-use the information that is available under this licence. + +## Copyright Notice + +© Crown Copyright 2026. This work has been developed by the National Digital Twin Programme and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + +Licensed under the Open Government Licence v3.0. + +You can view the full license at: https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/ \ No newline at end of file diff --git a/README.md b/README.md index 381825b..a0f5c8e 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,56 @@ -# node-lib +# README +**Repository:** `node-lib` +**Description:** `node-lib provides useful helper libraries for building Adaptors, Mappers and Projectors for the Integration Architecture Node Platform.` + +# Overview node-lib provides useful helper libraries for building Adaptors, Mappers and Projectors for the Integration Architecture Node Platform. ## Dependencies - - Python \>=3.10 - Kafka* node-lib uses `confluent-kafka` to manage connections to Kafka. Please see [confluent-kafka's compatability documentation](https://docs.confluent.io/platform/current/installation/versions-interoperability.html) to ensure you have a compatible Kafka instance. - ## Installation - ```shell pip install node-lib ``` ## Usage - For documentation on how to use node-lib, please see the [documentation index](https://github.com/National-Node-Net/node-lib/blob/main/docs/index.md). -## Licensing +## Public Funding Acknowledgment +This repository has been developed with public funding as part of the National Digital Twin Programme (NDTP), a UK Government initiative. NDTP, alongside its partners, has invested in this work to advance open, secure, and reusable digital twin technologies for any organisation, whether from the public or private sector, irrespective of size. + +## License +This repository contains both source code and documentation, which are covered by different licenses: +- **Code:** Originally developed by Telicent UK Ltd, now maintained by National Digital Twin Programme. Licensed under the [Apache License 2.0](LICENSE.md). +- **Documentation:** Licensed under the [Open Government Licence (OGL) v3.0](OGL_LICENSE.md). + +By contributing to this repository, you agree that your contributions will be licensed under these terms. + +See [LICENSE.md](LICENSE.md), [OGL_LICENSE.md](OGL_LICENSE.md), and [NOTICE.md](NOTICE.md) for details. + +## Security and Responsible Disclosure +We take security seriously. If you believe you have found a security vulnerability in this repository, please follow our responsible disclosure process outlined in `SECURITY.md`. + +## Software Bill of Materials (SBOM) +This project provides a Software Bill of Materials (SBOM) to help users and integrators understand its dependencies. + +### Current SBOM +Download the [latest SBOM for this codebase](../../dependency-graph/sbom) to view the current list of components used in this repository. + +## Contributing +We welcome contributions that align with the Programme’s objectives. Please read our `CONTRIBUTING.md` guidelines before submitting pull requests. + +## Acknowledgements +This repository has benefited from collaboration with various organisations. For a list of acknowledgments, see `ACKNOWLEDGEMENTS.md`. + +## Support and Contact +For questions or support, check our Issues or contact the NDTP team by emailing ndtp@businessandtrade.gov.uk. -This repository, including all source code, documentation, configuration files, and related materials, is licensed under the: +**Maintained by the National Digital Twin Programme (NDTP).** -**NDTP InnerSource Licence – Version 1.0** -See [LICENSE.md](LICENSE.md) for the full licence text. +© Crown Copyright 2026. This work has been developed by the National Digital Twin Programme and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md index b3ab6e9..c61ed8b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,8 +2,9 @@ **Repository:** `node-lib` **Description:** `Details the responsible disclosure process for security vulnerabilities.` +**SPDX-License-Identifier:** `OGL-UK-3.0` -## Responsible Disclosure +## Responsible Disclosure The National Digital Twin Programme (NDTP) follows a **Coordinated Vulnerability Disclosure (CVD)** process to ensure security risks are addressed responsibly. @@ -24,7 +25,7 @@ If you believe you have found a security vulnerability in this repository, **ple ### **How to Report a Security Issue** -1. **Do not open a public issue on GitHub.** Instead, report security concerns via email to **ndtp@businessandtrade.gov.uk**. +1. **Do not open a public issue on GitHub.** Instead, report security concerns via email to **[ndtp@businessandtrade.gov.uk]**. 2. **Provide detailed information about the vulnerability**, including: - A clear description of the issue. - Steps to reproduce the vulnerability. @@ -61,13 +62,14 @@ To help maintain security across NDTP repositories, we follow these principles: - Sensitive credentials **must not be included** in public repositories. - Security patches are applied in a timely manner, with priority given to critical vulnerabilities. +For more details, refer to our **Secure Development Guidelines** [Link to internal security policy, if available]. + --- **Maintained by the National Digital Twin Programme (NDTP).** -© Crown Copyright 2025. This work has been developed by the National Digital Twin Programme and is legally attributed to the Department for Business and Trade (UK) as the governing entity. - -Licensed under the NDTP InnerSource Licence – Version 1.0. +© Crown Copyright 2026. This work has been developed by the National Digital Twin Programme and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. -For full licensing terms, see [LICENSE.md](LICENSE.md). +Licensed under the Open Government Licence v3.0. +For full licensing terms, see [OGL_LICENCE.md](./OGL_LICENCE.md). diff --git a/debug.py b/debug.py index 16d68cb..444f296 100644 --- a/debug.py +++ b/debug.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import random @@ -72,11 +95,11 @@ def action_test(iterations: int = 1500, with_abort: bool = True): i = 0 try: while i < iterations: - action.records_processed(random.randint(100, 1000)) + action.records_processed(random.randint(100, 1000)) #NOSONAR python:S2245 time.sleep(random.uniform(0.001, 0.05)) i += 1 - if with_abort and random.randint(0, 1000) > 999: + if with_abort and random.randint(0, 1000) > 999: #NOSONAR python:S2245 action.aborted() exit(1) diff --git a/ia_map_lib/__init__.py b/ia_map_lib/__init__.py index d6597f4..9325e83 100644 --- a/ia_map_lib/__init__.py +++ b/ia_map_lib/__init__.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from ia_map_lib.adapter import Adapter, AutomaticAdapter from ia_map_lib.datasets import DCATDataSet, SimpleDataSet from ia_map_lib.mapper import Mapper diff --git a/ia_map_lib/action.py b/ia_map_lib/action.py index 0c650d1..92dca5e 100644 --- a/ia_map_lib/action.py +++ b/ia_map_lib/action.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import logging @@ -34,6 +57,8 @@ logger = logging.getLogger(__name__) +ITEM_TYPE = "item.type" +RECORD = "record" def __calculate_elapsed__(start: float | None) -> float | None: @@ -188,7 +213,7 @@ def telemetry_id(self): def __get_items_processed_rate__(self, options: CallbackOptions) -> Iterable[Observation]: total_elapsed = __calculate_elapsed__(self.processed_metric_timer) observation = Observation( - __calculate_rate__(self.processed_metric_counter, total_elapsed), {"item.type": "record"} + __calculate_rate__(self.processed_metric_counter, total_elapsed), {ITEM_TYPE: RECORD} ) self.processed_metric_timer = time.perf_counter() self.processed_metric_counter = 0 @@ -197,14 +222,14 @@ def __get_items_processed_rate__(self, options: CallbackOptions) -> Iterable[Obs def __get_items_output_rate__(self, options: CallbackOptions) -> Iterable[Observation]: total_elapsed = __calculate_elapsed__(self.output_metric_timer) observation = Observation( - __calculate_rate__(self.output_metric_counter, total_elapsed), {"item.type": "record"} + __calculate_rate__(self.output_metric_counter, total_elapsed), {ITEM_TYPE: RECORD} ) self.output_metric_timer = time.perf_counter() self.output_metric_counter = 0 return [observation] def __get_errors__(self, options: CallbackOptions) -> Iterable[Observation]: - return [Observation(self.error_count, {"item.type": "record"})] + return [Observation(self.error_count, {ITEM_TYPE: RECORD})] def reporter_kwargs(self): raise NotImplementedError() @@ -277,9 +302,9 @@ def started(self) -> None: If caller is using the `run()` method then this will be called automatically. """ if self.batch_timer is not None: - raise Exception('Action has already been started') + raise ValueError('Action has already been started') if self.total_timer is not None: - raise Exception('Action has already been started') + raise ValueError('Action has already been started') self.total_timer = time.perf_counter() self.batch_timer = self.total_timer @@ -323,9 +348,9 @@ def record_processed(self) -> None: self.counter += 1 self.processed_metric_counter += 1 tracer_span.set_attribute("action.counter", self.counter) - if self.reporting_batch_size > 0 and self.counter % self.reporting_batch_size == 0: - self.report_progress() - elif self.counter > self.next_batch_boundary: + if ( + self.reporting_batch_size > 0 and self.counter % self.reporting_batch_size == 0 + ) or self.counter > self.next_batch_boundary: self.report_progress() def record_read(self) -> None: @@ -355,9 +380,9 @@ def records_processed(self, count: int) -> None: :param count: Number of records processed """ self.counter += count - if self.reporting_batch_size > 0 and self.counter % self.reporting_batch_size == 0: - self.report_progress() - elif self.counter > self.next_batch_boundary: + if ( + self.reporting_batch_size > 0 and self.counter % self.reporting_batch_size == 0 + ) or self.counter > self.next_batch_boundary: self.report_progress() def report_progress(self) -> None: @@ -415,7 +440,7 @@ def finished(self) -> None: If the caller is using the `run()` method then this will be called automatically. """ if self.batch_timer is None: - raise Exception('Action has not been started') + raise ValueError('Action has not been started') # If we did not finish exactly on a reporting batch size report the stats for the final batch if self.counter % self.reporting_batch_size != 0: diff --git a/ia_map_lib/adapter.py b/ia_map_lib/adapter.py index b4e4530..e890f62 100644 --- a/ia_map_lib/adapter.py +++ b/ia_map_lib/adapter.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import logging diff --git a/ia_map_lib/config/__init__.py b/ia_map_lib/config/__init__.py index 02a7c9f..09e128a 100644 --- a/ia_map_lib/config/__init__.py +++ b/ia_map_lib/config/__init__.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from ia_map_lib.config.configSource import ConfigSource, EnvironmentSource from ia_map_lib.config.configurator import Configurator, OnError diff --git a/ia_map_lib/config/configSource.py b/ia_map_lib/config/configSource.py index 4c98140..01bbe88 100644 --- a/ia_map_lib/config/configSource.py +++ b/ia_map_lib/config/configSource.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + import os __license__ = """ diff --git a/ia_map_lib/config/configurator.py b/ia_map_lib/config/configurator.py index dc05cc5..d6feac9 100644 --- a/ia_map_lib/config/configurator.py +++ b/ia_map_lib/config/configurator.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + import logging import sys from collections.abc import Callable @@ -119,26 +142,28 @@ def get(self, config_key: str, default: Any = None, required: bool = False, desc self.__handle_errors__(f"Required Configuration Key {config_key} is not set. {description}", on_error) if converter is not None: - try: - value = converter(raw_value) - if self.debug: - logger.debug(f"Converted raw value {raw_value} into typed value {value} with type {type(value)}") - except Exception as e: - self.__handle_errors__( - f"Configuration Key {config_key} has raw value {raw_value} that failed value conversion: {e}", - on_error) + value = self._convert_value(config_key, raw_value, converter, on_error) else: value = raw_value - if required_type is not None: - if not isinstance(value, required_type): - self.__handle_errors__( - f"Configuration Key {config_key} has typed value {value} of type {type(value)}" - "which is not of the desired type {required_type}", - on_error) + if required_type is not None and not isinstance(value, required_type): + self.__handle_errors__( + f"Configuration Key {config_key} has typed value {value} of type {type(value)}" + "which is not of the desired type {required_type}", + on_error) return value + def _convert_value(self, config_key: str, raw_value: Any, converter: Callable[[str], Any], on_error: OnError) -> Any: + try: + if self.debug: + logger.debug(f"Converted raw value {raw_value} into typed value {value} with type {type(value)}") + return converter(raw_value) + except Exception as e: + self.__handle_errors__( + f"Configuration Key {config_key} has raw value {raw_value} that failed value conversion: {e}", on_error) + return None + def __handle_errors__(self, message: str, on_error: OnError): """ Handles configuration errors diff --git a/ia_map_lib/config/kafka.py b/ia_map_lib/config/kafka.py index d161720..16b51bf 100644 --- a/ia_map_lib/config/kafka.py +++ b/ia_map_lib/config/kafka.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import configparser diff --git a/ia_map_lib/datasets/__init__.py b/ia_map_lib/datasets/__init__.py index cd9c225..51f520c 100644 --- a/ia_map_lib/datasets/__init__.py +++ b/ia_map_lib/datasets/__init__.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from ia_map_lib.datasets.datasets import DCATDataSet, SimpleDataSet __license__ = """ diff --git a/ia_map_lib/datasets/datasets.py b/ia_map_lib/datasets/datasets.py index 2bd2eed..90d2948 100644 --- a/ia_map_lib/datasets/datasets.py +++ b/ia_map_lib/datasets/datasets.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import json @@ -39,7 +62,8 @@ class DCATDataSet(DataSet): def __init__(self, dataset_id: str, title: str, source_mime_type: str): super().__init__(dataset_id, title, source_mime_type) - self.tcat = 'http://ndtp.co.uk/catalog#' + # url gives 'Page not found' + self.tcat = 'https://ndtp.co.uk/catalog#' self.dataset_id_dataset = URIRef(f'{self.tcat}{self.dataset_id}_dataset') self.dataset_id_distribution = URIRef(f'{self.tcat}{self.dataset_id}_distribution') @@ -79,7 +103,8 @@ def registration_record(self, registration_fields: Mapping, headers: list[str | g.add(( qualified_attribution_bnode, URIRef(f'{DCAT}hadRole'), - URIRef('http://standards.iso.org/iso/19115/resources/Codelist/cat/codelists.xml#CI_RoleCode/owner') + # url is broken + URIRef('https://standards.iso.org/iso/19115/resources/Codelist/cat/codelists.xml#CI_RoleCode/owner') )) rights_bnode = BNode() @@ -103,7 +128,7 @@ def registration_record(self, registration_fields: Mapping, headers: list[str | g.add(( self.dataset_id_distribution, URIRef(f'{DCAT}mediaType'), - URIRef(f'http://www.iana.org/assignments/media-types/{self.source_mime_type}') + URIRef(f'https://www.iana.org/assignments/media-types/{self.source_mime_type}') )) g.add(( diff --git a/ia_map_lib/errors.py b/ia_map_lib/errors.py index a7454c9..0bd4cd1 100644 --- a/ia_map_lib/errors.py +++ b/ia_map_lib/errors.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + import datetime import importlib import json @@ -126,6 +149,3 @@ class PrintErrorHandler(ErrorHandler): def __send_record__(self, record: Record): print(str(record)) - - def close(self): - pass diff --git a/ia_map_lib/exceptions.py b/ia_map_lib/exceptions.py index 4a11cd1..765bc54 100644 --- a/ia_map_lib/exceptions.py +++ b/ia_map_lib/exceptions.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + __license__ = """ Copyright (c) Telicent Ltd. diff --git a/ia_map_lib/logging.py b/ia_map_lib/logging.py index 1ade19a..c54bb09 100644 --- a/ia_map_lib/logging.py +++ b/ia_map_lib/logging.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import json diff --git a/ia_map_lib/mapper.py b/ia_map_lib/mapper.py index 89b549b..5fe5b41 100644 --- a/ia_map_lib/mapper.py +++ b/ia_map_lib/mapper.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + import logging import uuid diff --git a/ia_map_lib/middleware/__init__.py b/ia_map_lib/middleware/__init__.py index 9816dd6..00b81ef 100644 --- a/ia_map_lib/middleware/__init__.py +++ b/ia_map_lib/middleware/__init__.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + __license__ = """ Copyright (c) Telicent Ltd. diff --git a/ia_map_lib/middleware/decode_token.py b/ia_map_lib/middleware/decode_token.py index da29361..ad3afdd 100644 --- a/ia_map_lib/middleware/decode_token.py +++ b/ia_map_lib/middleware/decode_token.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + import json import jwt @@ -73,7 +96,7 @@ def __call__(self, environ, start_response): def validate_token(self, token): try: - headers = jwt.get_unverified_header(token) + headers = jwt.get_unverified_header(token) #NOSONAR python:S5659 if self.jwks_url is not None: self.logger.debug("Validating token with jwks_url", log_type="GENERAL") jwks_client = jwt.PyJWKClient(self.jwks_url) diff --git a/ia_map_lib/projector.py b/ia_map_lib/projector.py index 31b30b2..c86bbae 100644 --- a/ia_map_lib/projector.py +++ b/ia_map_lib/projector.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from colored import Fore from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator diff --git a/ia_map_lib/records.py b/ia_map_lib/records.py index 1a7b5ba..2ffc838 100644 --- a/ia_map_lib/records.py +++ b/ia_map_lib/records.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import collections @@ -33,6 +56,8 @@ Record.value.__doc__ = "The value of the record, may be None if no value." Record.raw.__doc__ = "Provides access to the raw record type used internally by the data source, may be useful in " \ "some advanced use cases. " +NO_RECORD_ERROR = "No record provided" +NO_HEADER_KEY_ERROR = "No header key provided" @runtime_checkable @@ -184,9 +209,9 @@ def add_header(record: Record, header: str, value: str | dict | bytes | None) -> :raises ValueError: If no record/header key is provided """ if record is None: - raise ValueError("No record provided") + raise ValueError(NO_RECORD_ERROR) elif header is None: - raise ValueError("No header key provided") + raise ValueError(NO_HEADER_KEY_ERROR) new_headers = [] if record.headers is not None: @@ -206,7 +231,7 @@ def add_headers(record: Record, headers: list[tuple[str, str | bytes | dict | No :return: New record with the headers added """ if record is None: - raise ValueError("No record provided") + raise ValueError(NO_RECORD_ERROR) elif headers is None: raise ValueError("No new headers provided") elif not isinstance(headers, list): @@ -236,9 +261,9 @@ def replace_or_add_header(record: Record, header: str, value: str | bytes | None :return: New record with the header replaced or added """ if record is None: - raise ValueError("No record provided") + raise ValueError(NO_RECORD_ERROR) elif header is None: - raise ValueError("No header key provided") + raise ValueError(NO_HEADER_KEY_ERROR) header = header.casefold() new_headers = [] @@ -270,9 +295,9 @@ def remove_header(record: Record, header: str, value: str | bytes | None = None) :raises ValueError: If no record/header key is provided """ if record is None: - raise ValueError("No record provided") + raise ValueError(NO_RECORD_ERROR) elif header is None: - raise ValueError("No header key provided") + raise ValueError(NO_HEADER_KEY_ERROR) if record.headers is None: return record diff --git a/ia_map_lib/reporter.py b/ia_map_lib/reporter.py index 601e3b9..051f579 100644 --- a/ia_map_lib/reporter.py +++ b/ia_map_lib/reporter.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import json diff --git a/ia_map_lib/sinks/__init__.py b/ia_map_lib/sinks/__init__.py index 3e047b1..89b1914 100644 --- a/ia_map_lib/sinks/__init__.py +++ b/ia_map_lib/sinks/__init__.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from ia_map_lib.sinks.dataSink import DataSink from ia_map_lib.sinks.kafkaSink import KafkaSink from ia_map_lib.sinks.serializers import RdfSerializer, SerializerFunction, Serializers diff --git a/ia_map_lib/sinks/dataSink.py b/ia_map_lib/sinks/dataSink.py index 5b87507..022ddf0 100644 --- a/ia_map_lib/sinks/dataSink.py +++ b/ia_map_lib/sinks/dataSink.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from ia_map_lib.records import Record __license__ = """ diff --git a/ia_map_lib/sinks/dictSink.py b/ia_map_lib/sinks/dictSink.py index e1aa41f..ae612a3 100644 --- a/ia_map_lib/sinks/dictSink.py +++ b/ia_map_lib/sinks/dictSink.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from typing import Any from ia_map_lib import Record diff --git a/ia_map_lib/sinks/kafkaSink.py b/ia_map_lib/sinks/kafkaSink.py index c8f5036..0e62141 100644 --- a/ia_map_lib/sinks/kafkaSink.py +++ b/ia_map_lib/sinks/kafkaSink.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import inspect @@ -50,8 +73,11 @@ def __validate_kafka_serializer__(instance, name): # Could be a subclass of our defined SerializerFunction protocol in which case validate it immediately # Note, the Serializer class of confluent-kafka also matches the signature of our SerializerFunction so # must also confirm it is not a subclass of that. - if inspect.isclass(instance) and \ - issubclass(instance, SerializerFunction) and not issubclass(instance, Serializer): + if ( + inspect.isclass(instance) + and issubclass(instance, SerializerFunction) + and not issubclass(instance, Serializer) + ): validate_callable_protocol(instance, SerializerFunction) elif inspect.ismethod(instance) or inspect.isfunction(instance): @@ -61,18 +87,27 @@ def __validate_kafka_serializer__(instance, name): elif inspect.isclass(instance): raise TypeError( f"Provided {name} is not a function/method/Serializer instance but was the class {instance}," - "perhaps you meant to pass in an instance of this class instead?") + "perhaps you meant to pass in an instance of this class instead?" + ) else: - raise TypeError(f"Provided {name} is not a function/method/Serializer instance") + raise TypeError( + f"Provided {name} is not a function/method/Serializer instance" + ) class KafkaSink(DataSink): """A Data Sink backed by Apache Kafka""" - def __init__(self, topic: str, broker: str | list[str] | None = None, kafka_config: dict | None = None, - debug: bool = False, key_serializer: SerializerFunction | Serializer = Serializers.to_binary, - value_serializer: SerializerFunction | Serializer = Serializers.to_binary): + def __init__( + self, + topic: str, + broker: str | list[str] | None = None, + kafka_config: dict | None = None, + debug: bool = False, + key_serializer: SerializerFunction | Serializer = Serializers.to_binary, + value_serializer: SerializerFunction | Serializer = Serializers.to_binary, + ): """ Creates a new Kafka Data Sink that writes records to the specified topic @@ -100,13 +135,13 @@ def __init__(self, topic: str, broker: str | list[str] | None = None, kafka_conf warnings.warn( "Parameter 'broker' has been deprecated. Please provide 'kafka_config'.", DeprecationWarning, - stacklevel=2 + stacklevel=2, ) if debug is not None: warnings.warn( "Parameter 'debug' has been deprecated. Please use a logger to view debug messages.", DeprecationWarning, - stacklevel=2 + stacklevel=2, ) super().__init__(topic) @@ -118,7 +153,7 @@ def __init__(self, topic: str, broker: str | list[str] | None = None, kafka_conf # There are likely to be some config options specifically for consumers that will raise warnings. # These can be sensibly predicted and mitigated. - consumer_specific_config = ['auto.offset.reset', 'enable.auto.commit'] + consumer_specific_config = ["auto.offset.reset", "enable.auto.commit"] for exp_config in consumer_specific_config: if exp_config in kafka_config: del kafka_config[exp_config] @@ -135,6 +170,19 @@ def __init__(self, topic: str, broker: str | list[str] | None = None, kafka_conf self.key_serializer = key_serializer self.value_serializer = value_serializer + def normalize_headers(self, headers): + if isinstance(headers, list): + for i, header in enumerate(headers): + key, value = header + if not isinstance(value, bytes): + if isinstance(value, str): + headers[i] = (key, value.encode("utf-8")) + else: + raise TypeError( + "Record headers must be tuples where the value is given as bytes or a str" + ) + return headers + def send(self, record: Record = None): if record is None: return @@ -145,28 +193,20 @@ def send(self, record: Record = None): # Note that this is not an in-depth check of the headers since KafkaProducer will do a more detailed validation # of them when we try to send the record if record.headers is not None: - if isinstance(record.headers, list): - for i, header in enumerate(record.headers): - key, value = header - if not isinstance(value, bytes): - if isinstance(value, str): - record.headers[i] = (key, value.encode("utf-8")) - else: - raise TypeError("Record headers must be tuples where the value is given as bytes or a str") + record.headers = self.normalize_headers(record.headers) key = self.key_serializer(record.key) value = self.value_serializer(record.value) while True: try: - self.target.produce(self.topic, - key=key, - value=value, - headers=record.headers) + self.target.produce( + self.topic, key=key, value=value, headers=record.headers + ) self.target.poll(0) break except BufferError: - logger.debug('Waiting for buffer to clear') + logger.debug("Waiting for buffer to clear") self.target.poll(1) def close(self): diff --git a/ia_map_lib/sinks/listSink.py b/ia_map_lib/sinks/listSink.py index e7c3682..e46392e 100644 --- a/ia_map_lib/sinks/listSink.py +++ b/ia_map_lib/sinks/listSink.py @@ -1,3 +1,24 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. from ia_map_lib.records import Record diff --git a/ia_map_lib/sinks/serializers.py b/ia_map_lib/sinks/serializers.py index 6e4db16..c4f3704 100644 --- a/ia_map_lib/sinks/serializers.py +++ b/ia_map_lib/sinks/serializers.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import json diff --git a/ia_map_lib/sources/__init__.py b/ia_map_lib/sources/__init__.py index e7aaf24..317d45d 100644 --- a/ia_map_lib/sources/__init__.py +++ b/ia_map_lib/sources/__init__.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from ia_map_lib.sources.dataSource import DataSource from ia_map_lib.sources.deserializers import DeserializerFunction, Deserializers, RdfDeserializer from ia_map_lib.sources.kafkaSource import KafkaSource diff --git a/ia_map_lib/sources/dataSource.py b/ia_map_lib/sources/dataSource.py index 7a06466..db96105 100644 --- a/ia_map_lib/sources/dataSource.py +++ b/ia_map_lib/sources/dataSource.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations from collections.abc import Iterable diff --git a/ia_map_lib/sources/deserializers.py b/ia_map_lib/sources/deserializers.py index 80c4ae9..b5b39b6 100644 --- a/ia_map_lib/sources/deserializers.py +++ b/ia_map_lib/sources/deserializers.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import json diff --git a/ia_map_lib/sources/dictSource.py b/ia_map_lib/sources/dictSource.py index fe8209a..3230afa 100644 --- a/ia_map_lib/sources/dictSource.py +++ b/ia_map_lib/sources/dictSource.py @@ -1,3 +1,25 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + from collections.abc import Iterable diff --git a/ia_map_lib/sources/kafkaSource.py b/ia_map_lib/sources/kafkaSource.py index 712caf4..a5290c2 100644 --- a/ia_map_lib/sources/kafkaSource.py +++ b/ia_map_lib/sources/kafkaSource.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import inspect @@ -16,6 +39,7 @@ from ia_map_lib.utils import check_kafka_broker_available, generate_group_id, validate_callable_protocol logger = logging.getLogger(__name__) +AUTO_OFFSET_RESET_CONFIG = "auto.offset.reset" def __validate_kafka_deserializer__(instance, name): @@ -130,9 +154,9 @@ def __init__(self, topic, broker: str | list[str] | None = None, kafka_config: d check_kafka_broker_available(kafka_config) - reset_position = kafka_config.get('auto.offset.reset') + reset_position = kafka_config.get(AUTO_OFFSET_RESET_CONFIG) if reset_position is None: - kafka_config['auto.offset.reset'] = 'earliest' + kafka_config[AUTO_OFFSET_RESET_CONFIG] = 'earliest' group_id = kafka_config.get('group.id') if group_id is None or len(group_id) == 0: @@ -152,7 +176,7 @@ def __init__(self, topic, broker: str | list[str] | None = None, kafka_config: d kafka_config['enable.auto.commit'] = False self.broker = kafka_config['bootstrap.servers'] - self.reset_position = kafka_config['auto.offset.reset'] + self.reset_position = kafka_config[AUTO_OFFSET_RESET_CONFIG] self.needs_seek = False # Create the consumer @@ -219,25 +243,17 @@ def __next__(self): # going on with the KafkaConsumer we could be assigned partitions and start reading from them prior # to having the opportunity to seek to our desired position. If we do seek we do a fresh read so # that we get the correct record, otherwise we could return an incorrect record - logger.debug(f"Seeking based on reset_position={self.reset_position}") - if self.reset_position == 'beginning': - self.__seek_to_beginning__() - record = self.consumer.poll(timeout=1.0) - elif self.reset_position == 'end': - self.__seek_to_end__() - record = self.consumer.poll(timeout=1.0) + record = self.__perform_seek__() self.needs_seek = False + # If we were needing a seek i.e. we'd just been assigned a partition, but didn't have to explicitly seek # then the record will be None, and we'll loop back round again to try reading the next record if record is None: continue if record.error() is not None: - if "UNKNOWN_TOPIC_OR_PART" in record.error().__str__(): - raise SourceNotFoundException(source_name=self.get_source_name()) - else: - raise RuntimeError(record.error()) + self.__handle_record_errors__(record) self.last_offsets[TopicPartition(record.topic(), record.partition())] = record @@ -253,6 +269,20 @@ def __next__(self): raw=record ) + def __perform_seek__(self): + logger.debug(f"Seeking based on reset_position={self.reset_position}") + if self.reset_position == 'beginning': + self.__seek_to_beginning__() + return self.consumer.poll(timeout=1.0) + elif self.reset_position == 'end': + self.__seek_to_end__() + return self.consumer.poll(timeout=1.0) + + def __handle_record_errors__(self, record): + if "UNKNOWN_TOPIC_OR_PART" in record.error().__str__(): + raise SourceNotFoundException(source_name=self.get_source_name()) + raise RuntimeError(record.error()) + def remaining(self) -> int | None: remaining = None diff --git a/ia_map_lib/sources/listSource.py b/ia_map_lib/sources/listSource.py index fbb3940..6344fe9 100644 --- a/ia_map_lib/sources/listSource.py +++ b/ia_map_lib/sources/listSource.py @@ -1,3 +1,25 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + from collections.abc import Iterable diff --git a/ia_map_lib/status.py b/ia_map_lib/status.py index f0fb36d..6fa14d2 100644 --- a/ia_map_lib/status.py +++ b/ia_map_lib/status.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from enum import Enum __license__ = """ diff --git a/ia_map_lib/utils.py b/ia_map_lib/utils.py index 4282792..4ae8b72 100644 --- a/ia_map_lib/utils.py +++ b/ia_map_lib/utils.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import hashlib @@ -92,9 +115,6 @@ def validate_callable_protocol(function: Any, protocol: Any) -> None: if callable(protocol): sig_inspection = protocol.__call__ required_signature = inspect.signature(sig_inspection) # type: ignore - if required_signature is None: - raise TypeError(f"{protocol} is not a protocol whose validity can be checked") - has_self = False adj = 0 for i, parameter_tuple in enumerate(required_signature.parameters.items()): diff --git a/pyproject.toml b/pyproject.toml index 47a58ed..5005dc4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,15 +11,15 @@ requires-python = ">=3.9" license = {file = "LICENSE"} readme = "README.md" dependencies = [ - "colored==2.2.5", + "colored==2.3.0", "rdflib==7.1.3", "Werkzeug==3.1.3", "PyJWT==2.10.1", "requests==2.32.3", - "pytz==2024.2", + "pytz==2025.1", "confluent-kafka==2.8.0", - "opentelemetry-api==1.29.0", - "opentelemetry-sdk==1.29.0" + "opentelemetry-api==1.31.1", + "opentelemetry-sdk==1.31.1" ] classifiers = [ "Programming Language :: Python :: 3.9", @@ -37,14 +37,14 @@ classifiers = [ [project.optional-dependencies] dev = [ - "pre-commit==4.1.0", + "pre-commit==4.2.0", "ruff==0.9.4", - "types-pytz==2024.2.0.20241221", + "types-pytz==2025.1.0.20250318", "urllib3==2.3.0", - "types-requests==2.32.0.20241016", - "mypy==1.14.1", + "types-requests==2.32.0.20250306", + "mypy==1.15.0", "mkdocs==1.6.1", - "cyclonedx-bom==5.1.2" + "cyclonedx-bom==5.3.0" ] [tool.setuptools.dynamic] diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..2a61179 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,26 @@ +# Must be unique in a given SonarQube instance +sonar.projectKey=node-lib + + +# This is the name and version displayed in the SonarQube UI. +# Was mandatory prior to SonarQube 6.1. +sonar.projectName=node-lib +sonar.projectVersion=1.0 + +# Path is relative to the sonar-project.properties file. +sonar.sources=ia_map_lib/ + +# Encoding of the source code. Default is default system encoding +sonar.sourceEncoding=UTF-8 + +sonar.issue.ignore.multicriteria=e1,e2 +# python:S3776 : Cognitive Complexity of functions should not be too high +sonar.issue.ignore.multicriteria.e1.ruleKey=python:S3776 +sonar.issue.ignore.multicriteria.e1.resourceKey=**/ia_map_lib/mapper.py + +sonar.issue.ignore.multicriteria.e2.ruleKey=python:S3776 +sonar.issue.ignore.multicriteria.e2.resourceKey=**/ia_map_lib/utils.py + + + + diff --git a/tests/__init__.py b/tests/__init__.py index a02c3f6..37e6fbc 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +1,23 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + __all__: list[str] = [] diff --git a/tests/delaySink.py b/tests/delaySink.py index 1cf0082..7e0a12e 100644 --- a/tests/delaySink.py +++ b/tests/delaySink.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + import threading from ia_map_lib import Record diff --git a/tests/test_adapter.py b/tests/test_adapter.py index b88a141..784aa17 100644 --- a/tests/test_adapter.py +++ b/tests/test_adapter.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + import json import unittest from collections.abc import Iterable diff --git a/tests/test_data/__init__.py b/tests/test_data/__init__.py index e69de29..a8a7ebe 100644 --- a/tests/test_data/__init__.py +++ b/tests/test_data/__init__.py @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. \ No newline at end of file diff --git a/tests/test_data/utils_test_hosts.py b/tests/test_data/utils_test_hosts.py index c24b4d2..33ba558 100644 --- a/tests/test_data/utils_test_hosts.py +++ b/tests/test_data/utils_test_hosts.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + host_data = { 'hosts': [ "769e6291d353", diff --git a/tests/test_data_catalogue.py b/tests/test_data_catalogue.py index bf87608..3556203 100644 --- a/tests/test_data_catalogue.py +++ b/tests/test_data_catalogue.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import json diff --git a/tests/test_decode_token_middleware.py b/tests/test_decode_token_middleware.py index 0db17c2..8afc9b0 100644 --- a/tests/test_decode_token_middleware.py +++ b/tests/test_decode_token_middleware.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + import logging import unittest from unittest import mock diff --git a/tests/test_error_handler.py b/tests/test_error_handler.py index 2bc14fa..835a4cf 100644 --- a/tests/test_error_handler.py +++ b/tests/test_error_handler.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import json diff --git a/tests/test_generate_ids.py b/tests/test_generate_ids.py index 2ed6104..46a97cb 100644 --- a/tests/test_generate_ids.py +++ b/tests/test_generate_ids.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations from collections.abc import Iterable @@ -54,14 +77,14 @@ def test_id_is_name(self): def test_id_is_name_adapter(self): def my_func(record: Record) -> None: - pass + pass # This function is intentionally left empty as part of the test setup. action = Projector(source=ListSource(), has_error_handler=False, has_reporter=False, projector_function=my_func, target_store='Secure Agent', disable_metrics=True) self.assertEqual('Projector-from-In-Memory List(0 records)', action.generate_id()) def test_named_action(self): def my_func(record: Record) -> None: - pass + pass # This function is intentionally left empty as part of the test setup. action = Projector(source=ListSource(), has_error_handler=False, has_reporter=False, projector_function=my_func, target_store='Secure Agent', name='Test Action', disable_metrics=True) @@ -78,7 +101,7 @@ def test_id_is_name(self): def test_id_is_name_adapter(self): def my_func(record: Record) -> Record | list[Record] | None: - pass + pass # This function is intentionally left empty as part of the test setup. action = Mapper( source=ListSource(), target=ListSink(), has_error_handler=False, has_reporter=False, map_function=my_func, disable_metrics=True @@ -87,7 +110,7 @@ def my_func(record: Record) -> Record | list[Record] | None: def test_named_action(self): def my_func(record: Record) -> Record | list[Record] | None: - pass + pass # This function is intentionally left empty as part of the test setup. action = Mapper( source=ListSource(), target=ListSink(), has_error_handler=False, has_reporter=False, map_function=my_func, name='Test Action', disable_metrics=True diff --git a/tests/test_mapper.py b/tests/test_mapper.py index 918a3a6..070a1c8 100644 --- a/tests/test_mapper.py +++ b/tests/test_mapper.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import unittest diff --git a/tests/test_persistent_security_headers.py b/tests/test_persistent_security_headers.py index 546e4c8..803e274 100644 --- a/tests/test_persistent_security_headers.py +++ b/tests/test_persistent_security_headers.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import os diff --git a/tests/test_projector.py b/tests/test_projector.py index 1ed48f7..035a3c7 100644 --- a/tests/test_projector.py +++ b/tests/test_projector.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import unittest @@ -8,7 +31,7 @@ def __noop_projector__(record: Record) -> None: - pass + pass # This function is intentionally left empty as part of the test setup. def __fail_projector__(record: Record) -> None: diff --git a/tests/test_protocol_validation.py b/tests/test_protocol_validation.py index 8d2b081..8e224e0 100644 --- a/tests/test_protocol_validation.py +++ b/tests/test_protocol_validation.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import unittest @@ -33,7 +56,7 @@ def not_an_adder(a: int, b: int, c: bool) -> int: @runtime_checkable class Adder(Protocol): def __call__(self, x: int, y: int) -> int: - pass + pass # This function is intentionally left empty as part of the test setup. class UsableAdder(Adder): diff --git a/tests/test_records.py b/tests/test_records.py index 50829af..c8d446a 100644 --- a/tests/test_records.py +++ b/tests/test_records.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import json diff --git a/tests/test_reporter.py b/tests/test_reporter.py index 449e9c1..1e7bcce 100644 --- a/tests/test_reporter.py +++ b/tests/test_reporter.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + import json import time import unittest diff --git a/tests/test_serdes.py b/tests/test_serdes.py index 4b4726f..3d54c11 100644 --- a/tests/test_serdes.py +++ b/tests/test_serdes.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + from __future__ import annotations import inspect @@ -39,29 +62,23 @@ def __compare_rdf_graphs__(a: Any, b: Any) -> bool: return False return True - if not isinstance(a, Dataset): - a_iso = to_isomorphic(a) - else: - a_iso = to_isomorphic(a.get_context(identifier=DATASET_DEFAULT_GRAPH_ID)) # next(a.contexts())) - if not isinstance(b, Dataset): - b_iso = to_isomorphic(b) - else: - b_iso = to_isomorphic(b.get_context(identifier=DATASET_DEFAULT_GRAPH_ID)) # next(b.contexts())) - - # For debugging if tests aren't producing the expected results - if False: - print("A:") - print(a_iso.serialize(destination=None, encoding=None, format="nt11")) - print() - print("B:") - if isinstance(b, Dataset): - print("Full Dataset:") - print(b.serialize(destination=None, encoding=None, format="nquads")) - for _, ctx in enumerate(b.contexts()): - print(ctx.identifier) - print(b_iso.serialize(destination=None, encoding=None, format="nt11")) - - return a_iso == b_iso + def to_iso(graph): + return to_isomorphic(graph) if not isinstance(graph, Dataset) else to_isomorphic( + graph.get_context(identifier=DATASET_DEFAULT_GRAPH_ID) + ) +# For debugging if tests aren't producing the expected results +# if False: +# print("A:") +# print(a_iso.serialize(destination=None, encoding=None, format="nt11")) +# print() +# print("B:") +# if isinstance(b, Dataset): +# print("Full Dataset:") +# print(b.serialize(destination=None, encoding=None, format="nquads")) +# for _, ctx in enumerate(b.contexts()): +# print(ctx.identifier) +# print(b_iso.serialize(destination=None, encoding=None, format="nt11")) + return to_iso(a) == to_iso(b) class ExtendedSerializerFunction(SerializerFunction): @@ -246,24 +263,14 @@ def test_serdes_validation_01(self): self.assertTrue(inspect.ismethod(serializer) or inspect.isfunction(serializer)) self.assertTrue(inspect.ismethod(deserializer) or inspect.isfunction(deserializer)) - self.assertTrue(isinstance(RdfSerializer(), Serializer)) - self.assertTrue(isinstance(RdfDeserializer(), Deserializer)) + self.assertIsInstance(RdfSerializer(), Serializer) + self.assertIsInstance(RdfDeserializer(), Deserializer) self.assertFalse(inspect.ismethod(RdfSerializer) and inspect.isfunction(RdfSerializer)) self.assertFalse(inspect.ismethod(RdfDeserializer) and inspect.isfunction(RdfDeserializer)) def test_serdes_validation_02(self): self.assertFalse(inspect.ismethod(ExtendedSerializerFunction) or inspect.isfunction(ExtendedSerializerFunction)) - self.assertTrue(isinstance(ExtendedSerializerFunction, SerializerFunction)) - - with self.assertRaises(expected_exception=KafkaException): - KafkaSink( - topic="test", kafka_config={'bootstrap.servers': 'localhost:12345'}, - key_serializer=ExtendedSerializerFunction, value_serializer=ExtendedSerializerFunction - ) - - def test_serdes_validation_03(self): - self.assertFalse(inspect.ismethod(ExtendedSerializerFunction) or inspect.isfunction(ExtendedSerializerFunction)) - self.assertTrue(isinstance(ExtendedSerializerFunction, SerializerFunction)) + self.assertIsInstance(ExtendedSerializerFunction, SerializerFunction) with self.assertRaises(expected_exception=KafkaException): KafkaSink(topic="test", @@ -271,9 +278,9 @@ def test_serdes_validation_03(self): key_serializer=ExtendedSerializerFunction, value_serializer=ExtendedSerializerFunction) - def test_serdes_validation_04(self): + def test_serdes_validation_03(self): self.assertFalse(inspect.ismethod(ExtendedSerializerFunction) or inspect.isfunction(ExtendedSerializerFunction)) - self.assertTrue(isinstance(ExtendedSerializerFunction, SerializerFunction)) + self.assertIsInstance(ExtendedSerializerFunction, SerializerFunction) with self.assertRaises(expected_exception=KafkaException): KafkaSource(topic="test", @@ -283,7 +290,7 @@ def test_serdes_validation_04(self): def test_serdes_validation_05(self): self.assertFalse(inspect.ismethod(ExtendedSerializerFunction) or inspect.isfunction(ExtendedSerializerFunction)) - self.assertTrue(isinstance(ExtendedSerializerFunction, SerializerFunction)) + self.assertIsInstance(ExtendedSerializerFunction, SerializerFunction) with self.assertRaises(expected_exception=KafkaException): KafkaSource(topic="test", diff --git a/tests/test_sinks.py b/tests/test_sinks.py index 708a6d1..1e791d5 100644 --- a/tests/test_sinks.py +++ b/tests/test_sinks.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + import unittest from confluent_kafka import KafkaException diff --git a/tests/test_sources.py b/tests/test_sources.py index 99d5624..8ddb9ce 100644 --- a/tests/test_sources.py +++ b/tests/test_sources.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + import unittest from confluent_kafka import KafkaException diff --git a/tests/test_utils.py b/tests/test_utils.py index 4eff004..2e33dd0 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,3 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 +# Originally developed by Telicent Ltd.; subsequently adapted, enhanced, and maintained by the National Digital Twin Programme. + + +# Copyright (c) Telicent Ltd. + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Modifications made by the National Digital Twin Programme (NDTP) +# © Crown Copyright 2026. This work has been developed by the National Digital Twin Programme +# and is legally attributed to the UK's Department for Business, Innovation, Science and Trade (BIST) as the governing entity. + + import unittest from unittest.mock import MagicMock, patch