mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-09 22:31:41 +00:00
feat: Add University of Toronto FIPPA identifier patterns and tests (36 tests)
Add 3 UofT institutional identifiers (student/employee number, UTORid, TCard) covered under Ontario FIPPA. Includes pattern definitions, policy template sub-guardrail, compliance prompts, unit tests, and e2e tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f55fda3be7
commit
d35a95fc5d
6 changed files with 547 additions and 5 deletions
|
|
@ -597,6 +597,33 @@
|
|||
"description": "Detects Canadian postal codes (A1A 1A1 format, excludes invalid first-letter characters per Canada Post spec)",
|
||||
"keyword_pattern": "\\b(?:postal\\s*code|zip\\s*code|mailing\\s*address|address|code\\s*postal|postcode)\\b",
|
||||
"allow_word_numbers": false
|
||||
},
|
||||
{
|
||||
"name": "uoft_student_id",
|
||||
"display_name": "Student/Employee Number (University of Toronto)",
|
||||
"pattern": "\\b10\\d{8}\\b",
|
||||
"category": "Canadian Institutional Identifiers (FIPPA)",
|
||||
"description": "Detects University of Toronto student and employee numbers (10-digit, prefix '10'). Subject to Ontario FIPPA.",
|
||||
"keyword_pattern": "\\b(?:student\\s*id\\s*number|student\\s*number|employee\\s*id\\s*number|employee\\s*number|student\\s*id|employee\\s*id|utorid|uoft\\s*id|university\\s*of\\s*toronto|u\\s*of\\s*t)\\b",
|
||||
"allow_word_numbers": false
|
||||
},
|
||||
{
|
||||
"name": "uoft_utorid",
|
||||
"display_name": "UTORid (University of Toronto Login)",
|
||||
"pattern": "\\b[a-z]{2,6}\\d{1,4}\\b",
|
||||
"category": "Canadian Institutional Identifiers (FIPPA)",
|
||||
"description": "Detects University of Toronto UTORid login identifiers (e.g. smithj12). Context keywords are essential due to the generic format.",
|
||||
"keyword_pattern": "\\b(?:utorid|utoid|utor\\s*id|acorn|quercus|uoft\\s*login|university\\s*of\\s*toronto\\s*login|portal\\s*login|weblogin|shibboleth)\\b",
|
||||
"allow_word_numbers": false
|
||||
},
|
||||
{
|
||||
"name": "uoft_tcard",
|
||||
"display_name": "TCard Number (University of Toronto Campus ID)",
|
||||
"pattern": "\\b\\d{16}\\b",
|
||||
"category": "Canadian Institutional Identifiers (FIPPA)",
|
||||
"description": "Detects University of Toronto TCard campus ID card numbers (16-digit). Context keywords are critical to distinguish from payment card numbers.",
|
||||
"keyword_pattern": "\\b(?:tcard\\s*number|t-card\\s*number|campus\\s*card\\s*number|campus\\s*id\\s*number|library\\s*card\\s*number|student\\s*card\\s*number|id\\s*card\\s*number|tcard|t-card|campus\\s*card|campus\\s*id|library\\s*card|student\\s*card|id\\s*card|university\\s*card)\\b",
|
||||
"allow_word_numbers": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -2510,7 +2510,7 @@
|
|||
{
|
||||
"id": "canadian-pii-protection",
|
||||
"title": "Canadian PII Protection (PIPEDA)",
|
||||
"description": "Protects Canadian personal identifiers under PIPEDA and provincial privacy legislation. Masks Social Insurance Numbers (SIN), Ontario Health Insurance Plan (OHIP) numbers, Ontario driver's licence numbers, Canadian passport numbers, IRCC immigration documents, Canadian bank account routing information, postal codes, email addresses, and phone numbers.",
|
||||
"description": "Protects Canadian personal identifiers under PIPEDA, Ontario FIPPA, and provincial privacy legislation. Masks Social Insurance Numbers (SIN), Ontario Health Insurance Plan (OHIP) numbers, Ontario driver's licence numbers, Canadian passport numbers, IRCC immigration documents, Canadian bank account routing information, postal codes, email addresses, phone numbers, and University of Toronto institutional identifiers (student/employee numbers, UTORid, TCard).",
|
||||
"icon": "ShieldCheckIcon",
|
||||
"iconColor": "text-red-500",
|
||||
"iconBg": "bg-red-50",
|
||||
|
|
@ -2519,7 +2519,8 @@
|
|||
"ca-pii-health-drivers",
|
||||
"ca-pii-immigration",
|
||||
"ca-pii-financial",
|
||||
"ca-pii-contact-information"
|
||||
"ca-pii-contact-information",
|
||||
"ca-pii-institutional-ids"
|
||||
],
|
||||
"complexity": "Medium",
|
||||
"guardrailDefinitions": [
|
||||
|
|
@ -2657,23 +2658,53 @@
|
|||
"guardrail_info": {
|
||||
"description": "Masks email addresses, phone numbers (North American format), and Canadian postal codes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"guardrail_name": "ca-pii-institutional-ids",
|
||||
"litellm_params": {
|
||||
"guardrail": "litellm_content_filter",
|
||||
"mode": "pre_call",
|
||||
"patterns": [
|
||||
{
|
||||
"pattern_type": "prebuilt",
|
||||
"pattern_name": "uoft_student_id",
|
||||
"action": "MASK"
|
||||
},
|
||||
{
|
||||
"pattern_type": "prebuilt",
|
||||
"pattern_name": "uoft_utorid",
|
||||
"action": "MASK"
|
||||
},
|
||||
{
|
||||
"pattern_type": "prebuilt",
|
||||
"pattern_name": "uoft_tcard",
|
||||
"action": "MASK"
|
||||
}
|
||||
],
|
||||
"pattern_redaction_format": "[{pattern_name}_REDACTED]"
|
||||
},
|
||||
"guardrail_info": {
|
||||
"description": "Masks University of Toronto institutional identifiers (student/employee numbers, UTORid login, TCard campus ID) under Ontario FIPPA"
|
||||
}
|
||||
}
|
||||
],
|
||||
"templateData": {
|
||||
"policy_name": "canadian-pii-protection",
|
||||
"description": "Canadian PII protection policy under PIPEDA and provincial privacy legislation. Masks SIN, OHIP, Ontario driver's licence, passport, IRCC immigration documents, bank account routing info, postal codes, email, and phone numbers.",
|
||||
"description": "Canadian PII protection policy under PIPEDA, Ontario FIPPA, and provincial privacy legislation. Masks SIN, OHIP, Ontario driver's licence, passport, IRCC immigration documents, bank account routing info, postal codes, email, phone numbers, and University of Toronto institutional identifiers.",
|
||||
"guardrails_add": [
|
||||
"ca-pii-government-identifiers",
|
||||
"ca-pii-health-drivers",
|
||||
"ca-pii-immigration",
|
||||
"ca-pii-financial",
|
||||
"ca-pii-contact-information"
|
||||
"ca-pii-contact-information",
|
||||
"ca-pii-institutional-ids"
|
||||
],
|
||||
"guardrails_remove": []
|
||||
},
|
||||
"tags": [
|
||||
"PII Protection",
|
||||
"Canada"
|
||||
"Canada",
|
||||
"FIPPA"
|
||||
],
|
||||
"estimated_latency_ms": 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
"""
|
||||
Test University of Toronto identifier regex patterns added for FIPPA compliance.
|
||||
|
||||
Tests UTORid, student/employee number, and TCard number detection patterns.
|
||||
"""
|
||||
|
||||
from litellm.proxy.guardrails.guardrail_hooks.litellm_content_filter.patterns import (
|
||||
get_compiled_pattern,
|
||||
)
|
||||
|
||||
|
||||
class TestUofTStudentId:
|
||||
"""Test University of Toronto Student/Employee Number detection"""
|
||||
|
||||
def test_standard_student_number(self):
|
||||
pattern = get_compiled_pattern("uoft_student_id")
|
||||
assert pattern.search("1012345678") is not None
|
||||
|
||||
def test_another_valid_number(self):
|
||||
pattern = get_compiled_pattern("uoft_student_id")
|
||||
assert pattern.search("1099999999") is not None
|
||||
|
||||
def test_in_sentence(self):
|
||||
pattern = get_compiled_pattern("uoft_student_id")
|
||||
assert (
|
||||
pattern.search("My student number is 1012345678 for registration")
|
||||
is not None
|
||||
)
|
||||
|
||||
def test_prefix_must_be_10(self):
|
||||
"""All UofT numbers start with 10"""
|
||||
pattern = get_compiled_pattern("uoft_student_id")
|
||||
assert pattern.search("2012345678") is None
|
||||
|
||||
def test_too_few_digits_rejected(self):
|
||||
pattern = get_compiled_pattern("uoft_student_id")
|
||||
assert pattern.search("101234567") is None # 9 digits
|
||||
|
||||
def test_too_many_digits_rejected(self):
|
||||
pattern = get_compiled_pattern("uoft_student_id")
|
||||
assert pattern.search("10123456789") is None # 11 digits
|
||||
|
||||
def test_non_numeric_rejected(self):
|
||||
pattern = get_compiled_pattern("uoft_student_id")
|
||||
assert pattern.search("10abcdefgh") is None
|
||||
|
||||
|
||||
class TestUofTUTORid:
|
||||
"""Test University of Toronto UTORid detection"""
|
||||
|
||||
def test_standard_utorid(self):
|
||||
pattern = get_compiled_pattern("uoft_utorid")
|
||||
assert pattern.search("smithj12") is not None
|
||||
|
||||
def test_short_name_prefix(self):
|
||||
pattern = get_compiled_pattern("uoft_utorid")
|
||||
assert pattern.search("li5") is not None
|
||||
|
||||
def test_longer_name_prefix(self):
|
||||
pattern = get_compiled_pattern("uoft_utorid")
|
||||
assert pattern.search("kcheng42") is not None
|
||||
|
||||
def test_max_length_prefix(self):
|
||||
pattern = get_compiled_pattern("uoft_utorid")
|
||||
assert pattern.search("abcdef1234") is not None
|
||||
|
||||
def test_in_sentence(self):
|
||||
pattern = get_compiled_pattern("uoft_utorid")
|
||||
assert pattern.search("My UTORid is smithj12 for ACORN login") is not None
|
||||
|
||||
def test_single_letter_prefix_rejected(self):
|
||||
"""Minimum 2 letters required"""
|
||||
pattern = get_compiled_pattern("uoft_utorid")
|
||||
assert pattern.search("a1") is None
|
||||
|
||||
def test_too_many_letters_rejected(self):
|
||||
"""Maximum 6 letters"""
|
||||
pattern = get_compiled_pattern("uoft_utorid")
|
||||
assert pattern.search("abcdefg1") is None
|
||||
|
||||
def test_no_digits_rejected(self):
|
||||
pattern = get_compiled_pattern("uoft_utorid")
|
||||
assert pattern.search("smith") is None
|
||||
|
||||
def test_too_many_digits_rejected(self):
|
||||
"""Maximum 4 digits"""
|
||||
pattern = get_compiled_pattern("uoft_utorid")
|
||||
assert pattern.search("ab12345") is None
|
||||
|
||||
|
||||
class TestUofTTCard:
|
||||
"""Test University of Toronto TCard number detection"""
|
||||
|
||||
def test_standard_tcard(self):
|
||||
pattern = get_compiled_pattern("uoft_tcard")
|
||||
assert pattern.search("1234567890123456") is not None
|
||||
|
||||
def test_in_sentence(self):
|
||||
pattern = get_compiled_pattern("uoft_tcard")
|
||||
assert (
|
||||
pattern.search("My TCard number is 1234567890123456 for library access")
|
||||
is not None
|
||||
)
|
||||
|
||||
def test_too_few_digits_rejected(self):
|
||||
pattern = get_compiled_pattern("uoft_tcard")
|
||||
assert pattern.search("123456789012345") is None # 15 digits
|
||||
|
||||
def test_too_many_digits_rejected(self):
|
||||
pattern = get_compiled_pattern("uoft_tcard")
|
||||
assert pattern.search("12345678901234567") is None # 17 digits
|
||||
|
||||
def test_non_numeric_rejected(self):
|
||||
pattern = get_compiled_pattern("uoft_tcard")
|
||||
assert pattern.search("123456789012345a") is None
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
"""
|
||||
End-to-end tests for University of Toronto identifier patterns (FIPPA compliance).
|
||||
|
||||
Tests the complete guardrail with UofT patterns — validates that
|
||||
institutional identifiers are detected/masked and that clean prompts pass through.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from litellm.proxy.guardrails.guardrail_hooks.litellm_content_filter.content_filter import (
|
||||
ContentFilterGuardrail,
|
||||
)
|
||||
from litellm.types.guardrails import ContentFilterAction, ContentFilterPattern
|
||||
|
||||
|
||||
class TestUofTPolicyE2E:
|
||||
"""End-to-end tests for University of Toronto identifier patterns"""
|
||||
|
||||
def setup_uoft_guardrail(self):
|
||||
"""
|
||||
Setup guardrail with all UofT patterns (mimics the policy template sub-guardrail)
|
||||
"""
|
||||
patterns = [
|
||||
ContentFilterPattern(
|
||||
pattern_type="prebuilt",
|
||||
pattern_name="uoft_student_id",
|
||||
action=ContentFilterAction.MASK,
|
||||
),
|
||||
ContentFilterPattern(
|
||||
pattern_type="prebuilt",
|
||||
pattern_name="uoft_utorid",
|
||||
action=ContentFilterAction.MASK,
|
||||
),
|
||||
ContentFilterPattern(
|
||||
pattern_type="prebuilt",
|
||||
pattern_name="uoft_tcard",
|
||||
action=ContentFilterAction.MASK,
|
||||
),
|
||||
]
|
||||
guardrail = ContentFilterGuardrail(
|
||||
guardrail_name="test-uoft-ids",
|
||||
patterns=patterns,
|
||||
pattern_redaction_format="[{pattern_name}_REDACTED]",
|
||||
)
|
||||
return guardrail
|
||||
|
||||
# =====================
|
||||
# Student/Employee Number tests
|
||||
# =====================
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_student_number_masked(self):
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "My student number is 1012345678 for registration"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert "[UOFT_STUDENT_ID_REDACTED]" in output
|
||||
assert "1012345678" not in output
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_employee_id_masked(self):
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "Employee id 1099887766 needs access to the lab"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert "[UOFT_STUDENT_ID_REDACTED]" in output
|
||||
assert "1099887766" not in output
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_uoft_student_id_in_context(self):
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "University of Toronto student 1012345678 enrolled in CS"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert "[UOFT_STUDENT_ID_REDACTED]" in output
|
||||
assert "1012345678" not in output
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_student_number_clean_passes(self):
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "How do I find my U of T student number?"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert output == text
|
||||
|
||||
# =====================
|
||||
# UTORid tests
|
||||
# =====================
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_utorid_masked(self):
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "My UTORid is smithj12 for ACORN login"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert "[UOFT_UTORID_REDACTED]" in output
|
||||
assert "smithj12" not in result
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_utorid_quercus_context_masked(self):
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "Quercus login: kcheng42"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert "[UOFT_UTORID_REDACTED]" in output
|
||||
assert "kcheng42" not in output
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_utorid_acorn_context_masked(self):
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "Log in to ACORN with li5"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert "[UOFT_UTORID_REDACTED]" in output
|
||||
assert "li5" not in output
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_utorid_clean_passes(self):
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "How do I reset my UTORid password?"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert output == text
|
||||
|
||||
# =====================
|
||||
# TCard tests
|
||||
# =====================
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_tcard_masked(self):
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "My TCard number is 1234567890123456 for library access"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert "[UOFT_TCARD_REDACTED]" in output
|
||||
assert "1234567890123456" not in output
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_campus_card_masked(self):
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "Campus card 9876543210987654 needs reactivation"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert "[UOFT_TCARD_REDACTED]" in output
|
||||
assert "9876543210987654" not in output
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_student_card_masked(self):
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "Lost my student card 1111222233334444 yesterday"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert "[UOFT_TCARD_REDACTED]" in output
|
||||
assert "1111222233334444" not in output
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_tcard_clean_passes(self):
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "Where can I get a replacement TCard on campus?"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert output == text
|
||||
|
||||
# =====================
|
||||
# No false positives without context
|
||||
# =====================
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generic_10digit_no_context_passes(self):
|
||||
"""10-digit number starting with 10 but no keyword context should pass"""
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "The order total is 1012345678 units"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert output == text
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generic_short_word_no_context_passes(self):
|
||||
"""Generic short word with digits should not be masked without UTORid context"""
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "The variable abc123 is used in the code"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert output == text
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generic_16digit_no_context_passes(self):
|
||||
"""16-digit number without TCard context should not match TCard pattern"""
|
||||
guardrail = self.setup_uoft_guardrail()
|
||||
text = "Reference number 1234567890123456 for the shipment"
|
||||
result = await guardrail.apply_guardrail(
|
||||
inputs={"texts": [text]},
|
||||
request_data={},
|
||||
input_type="request",
|
||||
)
|
||||
output = result.get("texts", [])[0]
|
||||
assert output == text
|
||||
|
|
@ -248,4 +248,115 @@ export const canadianPiiCompliancePrompts: CompliancePrompt[] = [
|
|||
"What is the format of a Canadian postal code?",
|
||||
expectedResult: "pass",
|
||||
},
|
||||
|
||||
// =====================
|
||||
// UofT Student/Employee Number (should FAIL = detected/masked)
|
||||
// =====================
|
||||
{
|
||||
id: "ca-uoft-id-1",
|
||||
framework: "Canadian PII (FIPPA)",
|
||||
category: "UofT Student/Employee Number",
|
||||
categoryIcon: "graduation-cap",
|
||||
categoryDescription:
|
||||
"Detects University of Toronto student and employee numbers (10-digit, prefix '10') — protected under Ontario FIPPA.",
|
||||
prompt:
|
||||
"My student number is 1012345678 for course registration.",
|
||||
expectedResult: "fail",
|
||||
},
|
||||
{
|
||||
id: "ca-uoft-id-2",
|
||||
framework: "Canadian PII (FIPPA)",
|
||||
category: "UofT Student/Employee Number",
|
||||
categoryIcon: "graduation-cap",
|
||||
categoryDescription:
|
||||
"Detects University of Toronto student and employee numbers (10-digit, prefix '10') — protected under Ontario FIPPA.",
|
||||
prompt:
|
||||
"Employee id 1099887766 needs building access at the university.",
|
||||
expectedResult: "fail",
|
||||
},
|
||||
{
|
||||
id: "ca-uoft-id-3",
|
||||
framework: "Canadian PII (FIPPA)",
|
||||
category: "UofT Student/Employee Number",
|
||||
categoryIcon: "graduation-cap",
|
||||
categoryDescription:
|
||||
"Detects University of Toronto student and employee numbers (10-digit, prefix '10') — protected under Ontario FIPPA.",
|
||||
prompt:
|
||||
"How do I find my U of T student number?",
|
||||
expectedResult: "pass",
|
||||
},
|
||||
|
||||
// =====================
|
||||
// UTORid (should FAIL = detected/masked)
|
||||
// =====================
|
||||
{
|
||||
id: "ca-utorid-1",
|
||||
framework: "Canadian PII (FIPPA)",
|
||||
category: "UTORid Login",
|
||||
categoryIcon: "log-in",
|
||||
categoryDescription:
|
||||
"Detects University of Toronto UTORid login identifiers — protected under Ontario FIPPA.",
|
||||
prompt:
|
||||
"My UTORid is smithj12 for ACORN login.",
|
||||
expectedResult: "fail",
|
||||
},
|
||||
{
|
||||
id: "ca-utorid-2",
|
||||
framework: "Canadian PII (FIPPA)",
|
||||
category: "UTORid Login",
|
||||
categoryIcon: "log-in",
|
||||
categoryDescription:
|
||||
"Detects University of Toronto UTORid login identifiers — protected under Ontario FIPPA.",
|
||||
prompt:
|
||||
"Quercus login: kcheng42 needs password reset.",
|
||||
expectedResult: "fail",
|
||||
},
|
||||
{
|
||||
id: "ca-utorid-3",
|
||||
framework: "Canadian PII (FIPPA)",
|
||||
category: "UTORid Login",
|
||||
categoryIcon: "log-in",
|
||||
categoryDescription:
|
||||
"Detects University of Toronto UTORid login identifiers — protected under Ontario FIPPA.",
|
||||
prompt:
|
||||
"How do I reset my UTORid password?",
|
||||
expectedResult: "pass",
|
||||
},
|
||||
|
||||
// =====================
|
||||
// TCard (should FAIL = detected/masked)
|
||||
// =====================
|
||||
{
|
||||
id: "ca-tcard-1",
|
||||
framework: "Canadian PII (FIPPA)",
|
||||
category: "TCard Campus ID",
|
||||
categoryIcon: "credit-card",
|
||||
categoryDescription:
|
||||
"Detects University of Toronto TCard campus ID card numbers (16-digit) — protected under Ontario FIPPA.",
|
||||
prompt:
|
||||
"My TCard number is 1234567890123456 for library access.",
|
||||
expectedResult: "fail",
|
||||
},
|
||||
{
|
||||
id: "ca-tcard-2",
|
||||
framework: "Canadian PII (FIPPA)",
|
||||
category: "TCard Campus ID",
|
||||
categoryIcon: "credit-card",
|
||||
categoryDescription:
|
||||
"Detects University of Toronto TCard campus ID card numbers (16-digit) — protected under Ontario FIPPA.",
|
||||
prompt:
|
||||
"Campus card 9876543210987654 needs reactivation.",
|
||||
expectedResult: "fail",
|
||||
},
|
||||
{
|
||||
id: "ca-tcard-3",
|
||||
framework: "Canadian PII (FIPPA)",
|
||||
category: "TCard Campus ID",
|
||||
categoryIcon: "credit-card",
|
||||
categoryDescription:
|
||||
"Detects University of Toronto TCard campus ID card numbers (16-digit) — protected under Ontario FIPPA.",
|
||||
prompt:
|
||||
"Where can I get a replacement TCard on campus?",
|
||||
expectedResult: "pass",
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -543,6 +543,11 @@ const frameworkMeta: Record<string, { icon: string; description: string }> = {
|
|||
description:
|
||||
"Canadian PII detection under PIPEDA and provincial privacy legislation — masks SIN, OHIP, driver's licence, passport, immigration docs, bank accounts, and postal codes.",
|
||||
},
|
||||
"Canadian PII (FIPPA)": {
|
||||
icon: "graduation-cap",
|
||||
description:
|
||||
"Ontario FIPPA institutional identifier detection — masks University of Toronto student/employee numbers, UTORid logins, and TCard campus IDs.",
|
||||
},
|
||||
"Airline Brand Protection": {
|
||||
icon: "plane",
|
||||
description: "Destination vs competitor intent — avoid answering competitor comparison questions.",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue