Skip to content

Commit 0c0dc69

Browse files
authored
Merge pull request #53 from ruivieira/RHOAIENG-24896-tls
feat(RHOAIENG-24896): Add TLS cert support
2 parents df7a616 + 5d76653 commit 0c0dc69

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1000
-1432
lines changed

.github/workflows/build-and-push.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,11 @@ jobs:
132132
edit-mode: replace
133133
body: |
134134
PR image build and manifest generation completed successfully!
135-
135+
136136
📦 [PR image](https://quay.io/trustyai/trustyai-service-python-ci:${{ github.event.pull_request.head.sha }}): `quay.io/trustyai/trustyai-service-python-ci:${{ github.event.pull_request.head.sha }}`
137-
137+
138138
🗂️ [CI manifests](https://github.com/trustyai-explainability/trustyai-service-operator-ci/tree/service-python-${{ env.TAG }})
139-
139+
140140
```
141141
devFlags:
142142
manifests:

Dockerfile

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,15 @@ USER root
1515
# install mariadb connector from MariaDB Community Service package repository
1616
RUN if [[ "$EXTRAS" == *"mariadb"* ]]; then \
1717
curl -LsSO https://r.mariadb.com/downloads/mariadb_repo_setup && \
18-
echo "c4a0f3dade02c51a6a28ca3609a13d7a0f8910cccbb90935a2f218454d3a914a mariadb_repo_setup" | sha256sum -c - && \
1918
chmod +x mariadb_repo_setup && \
20-
./mariadb_repo_setup --mariadb-server-version="mariadb-10.6" && \
19+
./mariadb_repo_setup --mariadb-server-version="mariadb-11.4" && \
2120
dnf install -y MariaDB-shared MariaDB-devel; \
2221
fi
2322
RUN pip install uv==0.6.16 && \
2423
uv pip install ".[$EXTRAS]"
2524
COPY . .
2625
USER 1001
27-
EXPOSE 4443
26+
EXPOSE 8080 4443
2827

2928

30-
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8080"]
31-
#CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "4443", "--ssl-keyfile", "/etc/tls/internal/tls.key", "--ssl-certfile", "/etc/tls/internal/tls.crt"]
29+
CMD ["python", "-m", "src.main"]

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,24 @@ uv run uvicorn src.main --host 0.0.0.0 --port 8080
6565
podman run -t $IMAGE_NAME -p 8080:8080 .
6666
```
6767

68+
### 🔐 TLS Support
69+
The service supports TLS encryption and automatically detects certificates at startup:
70+
71+
- **With TLS certificates**: Runs on port 4443 (HTTPS)
72+
- **Without TLS certificates**: Runs on port 8080 (HTTP)
73+
74+
**Certificate locations** (configurable via environment variables):
75+
- Certificate: `/etc/tls/internal/tls.crt` (or `TLS_CERT_FILE`)
76+
- Private key: `/etc/tls/internal/tls.key` (or `TLS_KEY_FILE`)
77+
78+
**Environment variables**:
79+
- `TLS_CERT_FILE`: Path to TLS certificate file
80+
- `TLS_KEY_FILE`: Path to TLS private key file
81+
- `SSL_PORT`: HTTPS port (default: 4443)
82+
- `HTTP_PORT`: HTTP port (default: 8080)
83+
84+
The TLS implementation is fully compatible with the TrustyAI operator for seamless Kubernetes deployment.
85+
6886
## 🧪 Testing 🧪
6987
### Running All Tests
7088
To run all tests in the project:

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ authors = [{ name = "Rui Vieira" }, { name = "TrustyAI team" }]
66
requires-python = "~=3.11"
77
readme = "README.md"
88
dependencies = [
9-
"fastapi>=0.115.9,<0.120",
9+
"fastapi>=0.115.9,<0.117",
10+
"fastapi-utils>=0.8.0",
11+
"typing-inspect==0.9.0",
1012
"pandas>=2.2.3,<3",
1113
"prometheus-client>=0.21.1,<0.24",
1214
"pydantic>=2.4.2,<3",

src/core/metrics/fairness/group/group_average_odds_difference.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,20 @@
66

77
from src.core.metrics.fairness.fairness_metrics_utils import filter_rows_by_inputs, calculate_confusion_matrix
88

9+
910
class GroupAverageOddsDifference:
1011
"""
1112
Calculate group average odds difference.
1213
"""
13-
@ staticmethod
14+
15+
@staticmethod
1416
def calculate_model(
1517
samples: np.ndarray,
1618
model: ClassifierMixin,
1719
privilege_columns: List[int],
1820
privilege_values: List[int],
1921
postive_class: List[int],
20-
output_column: int
22+
output_column: int,
2123
):
2224
"""
2325
Calculate group average odds difference for model outputs.
@@ -32,7 +34,9 @@ def calculate_model(
3234
outputs = model.predict(samples)
3335
truth = np.append(samples, outputs, axis=1)
3436

35-
return GroupAverageOddsDifference.calculate(samples, truth, privilege_columns, privilege_values, postive_class, output_column)
37+
return GroupAverageOddsDifference.calculate(
38+
samples, truth, privilege_columns, privilege_values, postive_class, output_column
39+
)
3640

3741
@staticmethod
3842
def calculate(test, truth, privilege_columns, privilege_values, positive_class, output_column):
@@ -46,6 +50,7 @@ def calculate(test, truth, privilege_columns, privilege_values, positive_class,
4650
:param output_column the column where the output is located
4751
return group average odds difference, between -1 and 1
4852
"""
53+
4954
def privilege_filter(row):
5055
return np.array_equal(row[privilege_columns], privilege_values)
5156

@@ -55,11 +60,16 @@ def privilege_filter(row):
5560
truth_privileged = filter_rows_by_inputs(truth, privilege_filter)
5661
truth_unprivileged = filter_rows_by_inputs(truth, lambda row: not privilege_filter(row))
5762

58-
ucm = calculate_confusion_matrix(test_unprivileged[:, output_column], truth_unprivileged[:, output_column], positive_class)
59-
pcm = calculate_confusion_matrix(test_privileged[:, output_column], truth_privileged[:, output_column], positive_class)
63+
ucm = calculate_confusion_matrix(
64+
test_unprivileged[:, output_column], truth_unprivileged[:, output_column], positive_class
65+
)
66+
pcm = calculate_confusion_matrix(
67+
test_privileged[:, output_column], truth_privileged[:, output_column], positive_class
68+
)
6069

6170
utp, utn, ufp, ufn = ucm["tp"], ucm["tn"], ucm["fp"], ucm["fn"]
6271
ptp, ptn, pfp, pfn = pcm["tp"], pcm["tn"], pcm["fp"], pcm["fn"]
6372

64-
return (utp / (utp + ufn + 1e-10) - ptp / (ptp + pfn + 1e-10)) / 2 + \
65-
(ufp / (ufp + utn + 1e-10) - pfp / (pfp + ptn + 1e-10)) / 2
73+
return (utp / (utp + ufn + 1e-10) - ptp / (ptp + pfn + 1e-10)) / 2 + (
74+
ufp / (ufp + utn + 1e-10) - pfp / (pfp + ptn + 1e-10)
75+
) / 2

src/core/metrics/fairness/group/group_average_predictive_value_difference.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,20 @@
66

77
from src.core.metrics.fairness.fairness_metrics_utils import filter_rows_by_inputs, calculate_confusion_matrix
88

9+
910
class GroupAveragePredictiveValueDifference:
1011
"""
1112
Calculate group average predictive value difference.
1213
"""
14+
1315
@staticmethod
1416
def calculate_model(
1517
samples: np.ndarray,
1618
model: ClassifierMixin,
1719
privilege_columns: List[int],
1820
privilege_values: List[int],
1921
positive_class: int,
20-
output_column: int
22+
output_column: int,
2123
) -> float:
2224
"""
2325
Calculate group average predictive value difference for model outputs.
@@ -30,7 +32,9 @@ def calculate_model(
3032
"""
3133
outputs = model.predict(samples)
3234
truth = np.append(samples, outputs, axis=1)
33-
return GroupAveragePredictiveValueDifference.calculate(samples, truth, privilege_columns, privilege_values, positive_class, output_column)
35+
return GroupAveragePredictiveValueDifference.calculate(
36+
samples, truth, privilege_columns, privilege_values, positive_class, output_column
37+
)
3438

3539
@staticmethod
3640
def calculate(test, truth, privilege_columns, privilege_values, positive_class, output_column):
@@ -44,6 +48,7 @@ def calculate(test, truth, privilege_columns, privilege_values, positive_class,
4448
:param output_column the column where the output is located
4549
return group average predictive value difference, between -1 and 1
4650
"""
51+
4752
def privilege_filter(row):
4853
return np.array_equal(row[privilege_columns], privilege_values)
4954

@@ -53,11 +58,16 @@ def privilege_filter(row):
5358
truth_privileged = filter_rows_by_inputs(truth, privilege_filter)
5459
truth_unprivileged = filter_rows_by_inputs(truth, lambda row: not privilege_filter(row))
5560

56-
ucm = calculate_confusion_matrix(test_unprivileged[:, output_column], truth_unprivileged[:, output_column], positive_class)
57-
pcm = calculate_confusion_matrix(test_privileged[:, output_column], truth_privileged[:, output_column], positive_class)
61+
ucm = calculate_confusion_matrix(
62+
test_unprivileged[:, output_column], truth_unprivileged[:, output_column], positive_class
63+
)
64+
pcm = calculate_confusion_matrix(
65+
test_privileged[:, output_column], truth_privileged[:, output_column], positive_class
66+
)
5867

5968
utp, utn, ufp, ufn = ucm["tp"], ucm["tn"], ucm["fp"], ucm["fn"]
6069
ptp, ptn, pfp, pfn = pcm["tp"], pcm["tn"], pcm["fp"], pcm["fn"]
6170

62-
return (utp / (utp + ufp + 1e-10) - ptp / (ptp + pfp + 1e-10)) / 2 + \
63-
(ufn / (ufn + utn + 1e-10) - pfn / (pfn + ptn + 1e-10)) / 2
71+
return (utp / (utp + ufp + 1e-10) - ptp / (ptp + pfp + 1e-10)) / 2 + (
72+
ufn / (ufn + utn + 1e-10) - pfn / (pfn + ptn + 1e-10)
73+
) / 2

src/core/metrics/fairness/individual/individual_consistency.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import numpy as np
55
from sklearn.base import ClassifierMixin
66

7+
78
class IndividualConsistency:
89
"""
910
Calculate individual fairness in terms of consistency of predictions across similar inputs.
@@ -12,20 +13,17 @@ class IndividualConsistency:
1213
:param predictionProvider the model under inspection
1314
return the consistency measure
1415
"""
16+
1517
@staticmethod
16-
def calculate(
17-
proximity_function: Any,
18-
samples: np.ndarray,
19-
model: ClassifierMixin
20-
) -> float:
18+
def calculate(proximity_function: Any, samples: np.ndarray, model: ClassifierMixin) -> float:
2119
"""
2220
Calculate individual fairness.
2321
:param proximity_function: a function that finds the top k similar inputs, given a reference input and a list of inputs
2422
:param samples: a list of inputs to be tested for consistency
2523
:param model: the model under inspection
2624
return the consistency measure
2725
"""
28-
consistency = 1
26+
consistency = 1
2927
for sample in samples:
3028
prediction_outputs = model.predict(sample)
3129
if len(prediction_outputs) == 0:

0 commit comments

Comments
 (0)