Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 3 additions & 45 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,8 @@
# Runs on push to develop and on PRs targeting develop.
#
# Jobs:
# 1. quality — Install, lint, test & verify (tox), SonarCloud
# 2. trigger-staging-deploy — on push to develop only, triggers the
# Deploy ERSys Staging workflow on enity-resolution-ops via the
# GitHub workflow_dispatch API
#
# Required secrets:
# - SONAR_TOKEN: SonarCloud authentication token
# - CI_GH_TOKEN: org-level PAT for cross-repo workflow dispatch
# 1. quality — Install, lint, test & verify (tox)


name: CI

Expand Down Expand Up @@ -45,7 +39,7 @@ jobs:
# ------------------------------------------------------------------
- uses: actions/checkout@v6
with:
fetch-depth: 0 # Full history required for SonarCloud analysis
fetch-depth: 0

# ------------------------------------------------------------------
# Python & Poetry
Expand Down Expand Up @@ -99,39 +93,3 @@ jobs:
REDIS_HOST: localhost
REDIS_PORT: 6379
REDIS_PASSWORD: ""

# ------------------------------------------------------------------
# SonarCloud
# ------------------------------------------------------------------
- name: Check for SonarCloud Token
id: sonar_check
run: |
if [ -z "${{ secrets.SONAR_TOKEN }}" ]; then
echo "has_token=false" >> $GITHUB_OUTPUT
else
echo "has_token=true" >> $GITHUB_OUTPUT
fi

- name: SonarCloud scan
if: always() && steps.sonar_check.outputs.has_token == 'true'
uses: SonarSource/sonarqube-scan-action@v6
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

trigger-staging-deploy:
name: Trigger staging deploy
needs: quality
if: github.event_name == 'push' && github.repository_owner == 'meaningfy-ws'
runs-on: ubuntu-latest
env:
OPS_REPO: meaningfy-ws/enity-resolution-ops
DEPLOY_WORKFLOW: deploy-staging.yml
DEPLOY_REF: develop
steps:
- name: Trigger deploy workflow on ops repo
run: |
curl -sf -X POST \
-H "Authorization: token ${{ secrets.CI_GH_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com/repos/${OPS_REPO}/actions/workflows/${DEPLOY_WORKFLOW}/dispatches" \
-d '{"ref":"${{ env.DEPLOY_REF }}","inputs":{"repo":"${{ github.repository }}","sha":"${{ github.sha }}"}}'
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]


## [1.1.0-rc.6] - 2026-07-16

### Changed
* Disable logging of error traceback for controlled exceptions; the traceback logging is retained for uncontrolled exceptions (TEDSWS-529, TEDSWS-534)

### Removed
* SonarCloud integration, as it depended on contractor-specific configuration (TEDSWS-528).


## [1.0.0-rc.2] - 2026-06-30

### Changed
* ERSys installation instructions and related documentation improved (TEDSWS-520)
* Contractor-specific references removed from the source code repositories (TEDSWS-528)


## [1.1.0-rc.4] - 2026-06-30

### Changed
Expand Down
140 changes: 0 additions & 140 deletions sonar-project.properties

This file was deleted.

2 changes: 1 addition & 1 deletion src/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.1.0-rc.4
1.1.0-rc.6
22 changes: 17 additions & 5 deletions src/ere/services/entity_resolution_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
MentionRepository,
SimilarityRepository,
)
from ere.models.exceptions import ConflictError
from ere.models.resolver import (
CandidateCluster,
ClusterId,
Expand Down Expand Up @@ -229,8 +230,6 @@ def check_conflict(self, mention: Mention) -> None:
Raises:
ConflictError: If mention_id already exists with different attributes.
"""
from ere.models.exceptions import ConflictError

existing = self._mention_repo.find_by_id(mention.id)
if existing is not None and existing.attributes != mention.attributes:
raise ConflictError(
Expand Down Expand Up @@ -488,10 +487,11 @@ def process_request(self, request: ERERequest) -> EREResponse:
ere_request_id=request.ere_request_id,
timestamp=now,
)
except Exception as exc: # pylint: disable=broad-exception-caught
log.exception(
"Resolution error for mention %s",
except (ValueError, ConflictError) as exc:
log.error( # NOSONAR - intentionally no traceback for controlled exceptions
"Resolution error for mention %s: %s",
request.ere_request_id,
exc,
)
return EREErrorResponse(
ere_request_id=request.ere_request_id,
Expand All @@ -500,6 +500,18 @@ def process_request(self, request: ERERequest) -> EREResponse:
error_detail=str(exc),
timestamp=now,
)
except Exception: # pylint: disable=broad-exception-caught
log.exception(
"Unexpected error for mention %s",
request.ere_request_id,
)
return EREErrorResponse(
ere_request_id=request.ere_request_id,
error_type="InternalError",
error_title="Unexpected error",
error_detail="An unexpected error occurred",
timestamp=now,
)

def __call__(self, request: ERERequest) -> EREResponse:
"""Make the service callable."""
Expand Down
8 changes: 4 additions & 4 deletions src/infra/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ RUN groupadd --gid 1000 appuser && \

WORKDIR /app

# Copy only the virtual environment and necessary app files
COPY --from=builder /app/.venv /app/.venv
COPY --from=builder /app/ere /app/ere
COPY --from=builder /app/config /app/config
# Copy only the virtual environment and necessary app files — chown to appuser so non-root process can read
COPY --from=builder --chown=appuser:appuser /app/.venv /app/.venv
COPY --from=builder --chown=appuser:appuser /app/ere /app/ere
COPY --from=builder --chown=appuser:appuser /app/config /app/config
# Volume mount point for DuckDB persistent storage
RUN mkdir -p /data && chown appuser:appuser /data

Expand Down
40 changes: 20 additions & 20 deletions test/resources/rdf_mapping.yaml
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# Namespace prefix registry - used by rdf_mapper.py to resolve prefixed names in field paths
namespaces:
epo: "http://data.europa.eu/a4g/ontology#"
org: "http://www.w3.org/ns/org#"
locn: "http://www.w3.org/ns/locn#"
cccev: "http://data.europa.eu/m8g/"
# Entity type mappings: entity_type_string -> rdf_type + field property paths
# Property paths use / as separator for multi-hop traversal.
# Field names must match entity_fields in resolver.yaml (legal_name, country_code).
entity_types:
ORGANISATION:
rdf_type: "org:Organization"
fields:
legal_name: "epo:hasLegalName"
country_code: "cccev:registeredAddress/epo:hasCountryCode"
nuts_code: "cccev:registeredAddress/epo:hasNutsCode"
post_code: "cccev:registeredAddress/locn:postCode"
post_name: "cccev:registeredAddress/locn:postName"
thoroughfare: "cccev:registeredAddress/locn:thoroughfare"
# Namespace prefix registry - used by rdf_mapper.py to resolve prefixed names in field paths
namespaces:
epo: "http://data.europa.eu/a4g/ontology#"
org: "http://www.w3.org/ns/org#"
locn: "http://www.w3.org/ns/locn#"
cccev: "http://data.europa.eu/m8g/"

# Entity type mappings: entity_type_string -> rdf_type + field property paths
# Property paths use / as separator for multi-hop traversal.
# Field names must match entity_fields in resolver.yaml (legal_name, country_code).
entity_types:
ORGANISATION:
rdf_type: "org:Organization"
fields:
legal_name: "epo:hasLegalName"
country_code: "cccev:registeredAddress/epo:hasCountryCode"
nuts_code: "cccev:registeredAddress/epo:hasNutsCode"
post_code: "cccev:registeredAddress/locn:postCode"
post_name: "cccev:registeredAddress/locn:postName"
thoroughfare: "cccev:registeredAddress/locn:thoroughfare"
Loading