Skip to content

refactor(api-keys): answer which workspace owns a key, for other domains - #1452

Merged
peteski22 merged 4 commits into
mainfrom
feat/api-key-lookups
Sep 21, 2026
Merged

peteski22 merged 4 commits into
mainfrom
feat/api-key-lookups

Conversation

@peteski22

@peteski22 peteski22 commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Description

Nothing changes for someone using Otari. This adds the first part of the api-keys domain in its target shape: a service that another domain can ask which workspace owns an API key, and which keys sit in a set of workspaces.

Today the budgets domain answers both questions with its own queries on the API key table. In the target shape, a domain asks the owning domain's service instead of reading its tables. This PR adds that service and its repository. The two queries are copied from the organization budget module, which keeps its own copies for now.

Nothing in src calls the new service yet. The caller comes in Task 5.5 of the #1202 plan, which moves the organization budget surface onto a BudgetService that asks this service, and deletes the copied queries from the budgets module.

Three points about the design:

  • The lookups open no transaction of their own. They run in the caller's Unit of Work block and raise OutsideUnitOfWorkError when none is open.
  • The lookups do not check the tenant. A caller passes only key and workspace IDs from the caller's own organization.
  • The repository takes Never as its create and update schema types, so the generic create cannot be called on it. It writes no keys.

This builds on #1451, which is now merged: the repository only type-checks with that change, because the API key table is a declarative table.

No rule or baseline in scripts/check_architecture.py changes. The new service imports no database library, as the rule for new modules under services/ requires. docs/domains.md lists the two new packages under the api-keys domain, and four of its counts go up by one: service modules, repository modules, service packages and repository packages.

How to test it locally

make lint && make typecheck
env -u OTARI_API_KEY make test-unit
uv run pytest -n auto tests/integration
uv run --frozen --no-dev python scripts/oss_edition_smoke.py
make openapi-check && make postman-check
pnpm --dir web run client:generate && git diff --exit-code web/src/client/schema.ts

All of these pass on this branch, except tests/integration/test_mcp_dependency_ceiling.py, as in #1451.

tests/integration/test_api_key_service_lookups.py covers both lookups through the service: the owning workspace for a key, None for an unknown key, exactly the keys of the given workspaces, an empty list for no workspaces, and OutsideUnitOfWorkError outside a block. The commit that adds it comes first and fails with ModuleNotFoundError. ruff check also reports its import order at that commit, because ruff takes a module that does not exist yet for a third-party one.

PR Type

  • New Feature
  • Bug Fix
  • Refactor
  • Documentation
  • Infrastructure / CI

Relevant issues

Part of #1202: Task 5.2 of its plan. Builds on #1451 (Task 5.1). The first caller comes in Task 5.5.

Checklist

  • I understand the code I am submitting.
  • I have added or updated tests that cover my change (tests/unit, tests/integration).
  • I ran the Definition of Done checks locally (make lint, make typecheck, make test).
  • Documentation was updated where necessary.
  • If the API contract changed, I regenerated the OpenAPI spec (uv run python scripts/generate_openapi.py).
  • If this changes a rule in ARCHITECTURE.md or scripts/check_architecture.py, the description names the rule and says why.

AI Usage

  • No AI was used.
  • AI was used for drafting/refactoring.
  • This is fully AI-generated.

AI Model/Tool used:

Claude, via Claude Code.

Any additional AI details you'd like to share:

This was shared work. The change comes from the plan for #1202, and I set the scope and the rules it ran under: no edit to the budget service modules, no database import in the new service package, the domain map updated, a failing test as its own first commit, one small commit per step, and the project's comment standard for every text it adds or touches. Claude wrote the code and the tests under that direction, ran the checks, and drafted this description. Using Never for the schema types was Claude's proposal. I reviewed all four commits, and every added docstring, before the push.

  • I am an AI Agent filling out this form (check box if true)

@peteski22
peteski22 deployed to integration-tests September 21, 2026 18:00 — with GitHub Actions Active
@peteski22
peteski22 deployed to integration-tests September 21, 2026 18:00 — with GitHub Actions Active
@peteski22
peteski22 deployed to integration-tests September 21, 2026 18:00 — with GitHub Actions Active
@peteski22
peteski22 deployed to integration-tests September 21, 2026 18:00 — with GitHub Actions Active
@coderabbitai

coderabbitai Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 39 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: mozilla-ai/otari/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: e5d860fd-7eff-4042-89a3-056709b378a3

📥 Commits

Reviewing files that changed from the base of the PR and between 1f19ccd and b21d629.

📒 Files selected for processing (6)
  • docs/domains.md
  • src/gateway/repositories/api_keys/__init__.py
  • src/gateway/repositories/api_keys/api_key_repository.py
  • src/gateway/services/api_keys/__init__.py
  • src/gateway/services/api_keys/_service.py
  • tests/integration/test_api_key_service_lookups.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@peteski22
peteski22 deployed to integration-tests September 21, 2026 19:01 — with GitHub Actions Active
@peteski22
peteski22 deployed to integration-tests September 21, 2026 19:01 — with GitHub Actions Active
@peteski22
peteski22 deployed to integration-tests September 21, 2026 19:01 — with GitHub Actions Active
@peteski22
peteski22 deployed to integration-tests September 21, 2026 19:01 — with GitHub Actions Active
@peteski22
peteski22 marked this pull request as ready for review September 21, 2026 19:01
Which workspace owns a key, and which keys sit in a set of workspaces,
asked through an `ApiKeyService` on a Unit of Work. Both lookups raise
outside a block.

The file fails at this commit with `ModuleNotFoundError`, because
neither package exists yet. `ruff check` also reports its import order
until then, since it takes a missing module for a third-party one.
Two queries, copied from the organization budget surface, which keeps
its own copies for now: which workspace owns a key, and the IDs of the
keys in a set of workspaces. The repository runs on a Unit of Work and
takes `Never` for its create and update schemas, so the generic
`create` cannot be called on it.

The tests still fail at this commit: the service does not exist yet.
`ApiKeyService` is the api-keys domain's service in the target shape:
it receives its repository and imports no database library. Its two
methods delegate to the repository and open no block of their own, so
they run in the caller's transaction.

Nothing in `src` calls it yet.
The api-keys domain gains `services/api_keys/` and
`repositories/api_keys/`. The counts of service modules, repository
modules and domain packages go up by one each.
@peteski22
peteski22 deployed to integration-tests September 21, 2026 19:11 — with GitHub Actions Active
@peteski22
peteski22 deployed to integration-tests September 21, 2026 19:11 — with GitHub Actions Active
@peteski22
peteski22 deployed to integration-tests September 21, 2026 19:11 — with GitHub Actions Active
@peteski22
peteski22 deployed to integration-tests September 21, 2026 19:11 — with GitHub Actions Active
@peteski22
peteski22 merged commit d311450 into main Sep 21, 2026
18 checks passed
@peteski22
peteski22 deleted the feat/api-key-lookups branch September 21, 2026 19:14

This branch was successfully deployed

1 active deployment
integration-tests — b21d6298 Deployed Sep 21, 2026 by peteski22 via test-integration (2/4) #2390
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants