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
10 changes: 10 additions & 0 deletions api/ee/src/core/starter_credits_bridge/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from ee.src.core.starter_credits_bridge.client import StarterCreditsProxyClient
from ee.src.core.starter_credits_bridge.types import (
DEVELOPMENT_POLICY_VALUES,
PLUS_ALIAS_ALLOWLIST_DOMAINS,
KeyAliasExistsError,
MintedKey,
MintPolicy,
Expand Down Expand Up @@ -612,8 +613,17 @@ async def _mint_policy_allows(
domain = _email_domain(organization_email)
freemail = policy.is_freemail(domain)

if "+" in local_part and domain not in PLUS_ALIAS_ALLOWLIST_DOMAINS:
log.warning(
"[starter_credits_bridge] policy refused mint; skipping seed",
rule="plus_local_part",
domain=domain,
)
return False

if (
not freemail
and domain not in PLUS_ALIAS_ALLOWLIST_DOMAINS
and policy.block_digit_locals
and any(character.isdigit() for character in local_part)
):
Expand Down
4 changes: 4 additions & 0 deletions api/ee/src/core/starter_credits_bridge/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@
"bol.com.br",
)

# Plus-tags (`jane+1@gmail.com`) are one inbox and many grant-eligible strings.
# Internal testers who need a plus tag use this domain.
PLUS_ALIAS_ALLOWLIST_DOMAINS: tuple[str, ...] = ("agenta.ai",)


class MintPolicy(BaseModel):
"""Mint policy: velocity caps, domain classification, eligibility rules, and
Expand Down
36 changes: 36 additions & 0 deletions api/ee/tests/pytest/unit/test_starter_credits_bridge_seeding.py
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,28 @@ async def test_digit_rule_can_be_disabled_by_policy(self):

assert await service._mint_policy_allows("john99@acme.test", policy) is True

@pytest.mark.parametrize(
"address",
["person+trial@freemail.test", "person+trial@acme.test"],
)
async def test_plus_local_part_refuses_before_any_counter(self, address):
assert await service._mint_policy_allows(address, _policy()) is False
assert self.engine.counts == {}

async def test_plus_local_part_allows_an_address_without_a_plus(self):
assert (
await service._mint_policy_allows("person@freemail.test", _policy()) is True
)

@pytest.mark.parametrize(
"address",
["person+trial@agenta.ai", "person+1@Agenta.AI"],
)
async def test_plus_local_part_allows_the_agenta_domain(self, address):
policy = _policy(work_domain_daily=10)

assert await service._mint_policy_allows(address, policy) is True

async def test_global_hourly_cap_blocks(self):
policy = _policy(global_hourly=2)

Expand Down Expand Up @@ -1108,6 +1130,20 @@ async def test_a_digit_local_refusal_names_the_rule_and_the_domain(self):
assert fields["domain"] == "acme.test"
assert "john99" not in repr((message, fields))

async def test_a_plus_local_refusal_names_only_the_rule_and_domain(self):
assert (
await service._mint_policy_allows(
"person+private@freemail.test",
_policy(),
)
is False
)

message, fields = self.records[-1]
assert fields == {"rule": "plus_local_part", "domain": "freemail.test"}
assert "person" not in repr((message, fields))
assert "private" not in repr((message, fields))

async def test_a_velocity_refusal_names_the_rule_and_the_domain(self):
policy = _policy(work_domain_daily=1)

Expand Down
Loading