Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
166 commits
Select commit Hold shift + click to select a range
d6b4849
Merge branch 'sync-main' into 'enterprise'
Jun 3, 2026
f4628fc
feat(mcp): add tools to manage database connections
luis-dk May 28, 2026
48f0235
Merge branch 'mcp-connections' into 'enterprise'
Jun 3, 2026
35157f2
feat(mcp): accept hygiene issue id in source data tools
luis-dk Jun 1, 2026
bc6b46e
Merge branch 'mcp-issues-source-data' into 'enterprise'
Jun 3, 2026
0e0c35e
feat(mcp): add tools to manage table group
luis-dk May 28, 2026
4ba412a
Merge branch 'mcp-table-groups' into 'enterprise'
Jun 4, 2026
91a3fb7
fix(profiling): tolerate NULL max_query_chars in row-count chunking
luis-dk Jun 4, 2026
b6e8f29
fix(test-execution): tolerate NULL max_query_chars in CAT batching
luis-dk Jun 4, 2026
f6abfa3
refactor(connection): reuse DEFAULT_MAX_QUERY_CHARS constant
luis-dk Jun 4, 2026
7235fde
Merge branch 'fix/handle-null-max-chars' into 'enterprise'
Jun 4, 2026
71fa285
refactor(mcp,api): run-kind labels, shared status labels, API schema …
rboni-dk Jun 4, 2026
104ae70
Merge branch 'refactor/TG-1116-misc-cleanup' into 'enterprise'
Jun 4, 2026
f30a932
refactor(runs): read run lifecycle through a job_execution relationship
rboni-dk Jun 4, 2026
ec7e4ab
feat(test-definitions): support copy/move across projects (TG-1075)
diogodk May 22, 2026
c34d457
Merge branch 'feat/TG-1075-cross-project-copy' into 'enterprise'
diogodk Jun 5, 2026
7ff7b60
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1115-ad…
Jun 5, 2026
f2ec742
fix(mcp): consistent error surfacing and scope validation
rboni-dk Jun 4, 2026
3e41506
feat(mcp): surface stable-pass count in compare_test_runs
rboni-dk Jun 5, 2026
b3324a3
Merge branch 'fix/TG-1119-mcp-error-scope-hardening' into 'enterprise'
Jun 5, 2026
43b0619
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1093-mc…
Jun 5, 2026
db6b1c6
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1115-ad…
Jun 5, 2026
6c42249
Merge branch 'feat/TG-1093-mcp-compare-runs-stable-pass-count' into '…
Jun 6, 2026
3640863
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1115-ad…
Jun 6, 2026
89bb4ec
fix(test-execution): render empty baseline/tolerance params as NULL
aarthy-dk Jun 4, 2026
4d2eaca
fix(profiling): skip sampling on views where the sample clause reject…
aarthy-dk Jun 4, 2026
a13cce0
feat(catalog): surface object type and warn when views skip sampling
aarthy-dk Jun 5, 2026
c38f573
Merge branch 'feat/TG-1115-add-job-execution-relationship-to-run-mode…
Jun 8, 2026
4f0134b
Merge remote-tracking branch 'origin/enterprise' into misc-fixes
Jun 8, 2026
10f8a59
refactor(catalog): tighten object_type typing and mssql sampleable set
aarthy-dk Jun 8, 2026
504c6ab
Merge branch 'misc-fixes' into 'enterprise'
Jun 8, 2026
3133a1f
refactor: extract reusable test-result disposition service
luis-dk Jun 1, 2026
01124a6
feat(mcp): add test-result disposition tools
luis-dk Jun 1, 2026
683b51c
Merge branch 'mcp-testresult-disposition' into 'enterprise'
Jun 8, 2026
ed82df7
fix(mcp): support modern TLS ciphers and port-less origins for hosted…
aarthy-dk Jun 9, 2026
72dbb12
Merge branch 'fix/mcp-hosted-gateway-connectivity' into 'enterprise'
Jun 9, 2026
fad9a27
feat(mcp): add data catalog convenience tools
luis-dk Jun 8, 2026
7797ba9
Merge branch 'mcp-data-catalog-1' into 'enterprise'
luis-dk Jun 9, 2026
832f7b5
fix: match SQL Server schema names case-sensitively in profiling DDF
aarthy-dk Jun 9, 2026
1334876
refactor(runs): deduplicate run tables against job_executions
rboni-dk Jun 6, 2026
7673905
fix(mcp): allow the server's own port-less host in the transport allo…
aarthy-dk Jun 10, 2026
f7ad98c
feat(mcp): filter test-run and profiling-run lists by schedule (TG-1117)
rboni-dk Jun 10, 2026
2746a70
feat(mcp): add update_catalog_metadata write tool
luis-dk Jun 9, 2026
625bc07
Merge branch 'mcp-data-catalog-metadata' into 'enterprise'
Jun 10, 2026
7621301
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1117-mc…
Jun 10, 2026
f3c628f
Merge remote-tracking branch 'origin/enterprise' into fix/mcp-allowli…
Jun 10, 2026
d9d1351
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1047-de…
Jun 10, 2026
4984a74
Merge remote-tracking branch 'origin/enterprise' into fix/mssql-schem…
Jun 10, 2026
43ec6f0
Merge branch 'feat/TG-1117-mcp-filter-runs-by-schedule' into 'enterpr…
Jun 10, 2026
78ada67
Merge remote-tracking branch 'origin/enterprise' into fix/mcp-allowli…
Jun 10, 2026
0d53150
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1047-de…
Jun 10, 2026
3216d15
feat(mcp): add entity read tools for projects, connections, table gro…
diogodk Jun 1, 2026
415e552
Merge remote-tracking branch 'origin/enterprise' into fix/mssql-schem…
Jun 10, 2026
13eff2b
refactor(mcp): apply TG-1053 review feedback
diogodk Jun 9, 2026
2f129c1
Merge branch 'feat/TG-1053-mcp-entity-read' into 'enterprise'
Jun 10, 2026
768859b
Merge remote-tracking branch 'origin/enterprise' into fix/mcp-allowli…
Jun 10, 2026
0a85164
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1047-de…
Jun 10, 2026
ff16500
Merge remote-tracking branch 'origin/enterprise' into fix/mssql-schem…
Jun 10, 2026
5afa6a6
Merge branch 'fix/mcp-allowlist-server-own-host' into 'enterprise'
Jun 10, 2026
93b65a3
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1047-de…
Jun 10, 2026
c40bc57
Merge remote-tracking branch 'origin/enterprise' into fix/mssql-schem…
Jun 10, 2026
d37ae12
fix(table-groups): gate profile_flag_pii edits on view_pii permission
luis-dk Jun 10, 2026
3f22175
Merge branch 'fix/table-group-pii-checkbox' into 'enterprise'
Jun 10, 2026
d051ca7
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1047-de…
Jun 10, 2026
fd04203
Merge remote-tracking branch 'origin/enterprise' into fix/mssql-schem…
Jun 10, 2026
644a152
feat(api): normalize run-summary count shapes (TG-1121)
rboni-dk Jun 11, 2026
c5a8fee
feat(mcp): add monitor read tools — group summary and per-table inven…
diogodk Jun 11, 2026
2e3788f
Merge branch 'fix/mssql-schema-case-sensitive' into 'enterprise'
Jun 11, 2026
cf6b34f
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1121-no…
Jun 11, 2026
bebf748
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1090-mc…
Jun 11, 2026
100a40a
refactor(api): TD export/import domain exceptions and version marker
rboni-dk Jun 11, 2026
e715c55
fix(monitors): store freshness staleness threshold for full-week acti…
aarthy-dk Jun 12, 2026
e091289
Merge branch 'fix/freshness-staleness-active-schedule' into 'enterprise'
Jun 12, 2026
c181259
Merge remote-tracking branch 'origin/enterprise' into refactor/TG-112…
Jun 12, 2026
82d7074
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1121-no…
Jun 12, 2026
0d9238d
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1090-mc…
Jun 12, 2026
cc905ab
refactor(runs): apply TG-1047 review feedback
rboni-dk Jun 15, 2026
9f60020
refactor(runs): renumber migration 0194 -> 0195
rboni-dk Jun 15, 2026
094ad71
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1047-de…
rboni-dk Jun 15, 2026
c618241
Merge branch 'refactor/TG-1122-td-export-import-domain-errors' into '…
Jun 15, 2026
3bdfeab
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1121-no…
Jun 15, 2026
c23fc44
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1047-de…
Jun 15, 2026
72bdcf3
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1090-mc…
Jun 15, 2026
e5ed1fd
fix(profiling): prevent integer overflow in Invalid_Zip3_USA prevalen…
aarthy-dk Jun 15, 2026
da00f50
fix(security): patch HIGH/CRITICAL image CVEs
aarthy-dk Jun 15, 2026
6360df5
fix(db): grant write access to project_memberships table
aarthy-dk Jun 15, 2026
ba66324
Merge branch 'feat/TG-1047-deduplicate-run-tables' into 'enterprise'
Jun 15, 2026
ec669e6
Merge remote-tracking branch 'origin/enterprise' into fix/TG-1120-mis…
Jun 15, 2026
b0e1250
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1090-mc…
Jun 15, 2026
68ebb0c
Merge branch 'fix/TG-1120-misc-fixes' into 'enterprise'
Jun 15, 2026
e0da5a3
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1090-mc…
Jun 15, 2026
66dcf5d
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1121-no…
rboni-dk Jun 15, 2026
b11eaae
Merge branch 'feat/TG-1121-normalize-run-summary-count-shapes' into '…
Jun 16, 2026
4fda326
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1090-mc…
Jun 16, 2026
32ffc20
refactor(mcp): apply TG-1090 round-2 review feedback
diogodk Jun 16, 2026
2de9b0b
refactor(mcp): collapse monitor dashboard helpers and close two unit-…
diogodk Jun 16, 2026
1c71604
Merge branch 'feat/TG-1090-mcp-monitors-l1' into 'enterprise'
Jun 16, 2026
4dbea0e
ci: bump base image to v17
Jun 16, 2026
6bbfd75
refactor(mcp): remove connection write tools from the core connection…
rboni-dk Jun 16, 2026
32b1d82
feat(mcp): add plugin MCP-tools hook and promote shared connection he…
rboni-dk Jun 16, 2026
885053f
test: extract shared unit-test fixtures to testgen.testing (TG-1124)
rboni-dk Jun 16, 2026
e9d1604
Merge branch 'feat/TG-1124-mcp-enterprise-gating' into 'enterprise'
Jun 17, 2026
3b00bba
fix(mcp): keep testgen.testing out of the built wheel; tidy connectio…
rboni-dk Jun 17, 2026
4cba302
Merge branch 'fix/TG-1124-os-core-followups' into 'enterprise'
Jun 17, 2026
25210be
feat(mcp): monitor lifecycle & settings tools (TG-1094)
rboni-dk Jun 9, 2026
ede8589
fix(security): bump cryptography to 48.0.1 for patched bundled OpenSSL
aarthy-dk Jun 17, 2026
1b55a9c
fix(monitors): show error icon over anomaly count in monitor table cell
diogodk Jun 16, 2026
70bf71e
Merge branch 'fix/cryptography-48-openssl' into 'enterprise'
Jun 17, 2026
6ced309
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1094-mc…
Jun 17, 2026
ac30cb8
Merge remote-tracking branch 'origin/enterprise' into fix/TG-1126-mon…
Jun 17, 2026
4a61105
feat(mcp): add export_tests and import_tests tools
rboni-dk Jun 11, 2026
15d0a1b
Merge branch 'fix/TG-1126-monitor-error-cell-render' into 'enterprise'
Jun 18, 2026
733a72d
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1098-mc…
Jun 18, 2026
ffb3cf5
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1094-mc…
Jun 18, 2026
3ce0373
feat(api): add test run results endpoint
rboni-dk Jun 18, 2026
b732299
refactor(api): apply TG-1107 review feedback
rboni-dk Jun 19, 2026
abf2959
Merge branch 'feat/TG-1107-api-test-run-results-endpoint' into 'enter…
Jun 19, 2026
5fdbd2d
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1098-mc…
Jun 19, 2026
3460a7b
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1094-mc…
Jun 19, 2026
34d8947
refactor(mcp): trim import_tests docstring to purpose line per review
rboni-dk Jun 22, 2026
2a349c4
Merge branch 'feat/TG-1098-mcp-test-definition-export-and-import' int…
Jun 22, 2026
8a129ac
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1094-mc…
Jun 22, 2026
2e42e43
fix: use cross-platform date formatting for Excel export and schedule…
FernandezAstor Jun 9, 2026
7da561a
fix: extend cross-platform date formatting to all remaining sites
FernandezAstor Jun 17, 2026
0bd1764
fix: remove extra blank line in cron_service imports to satisfy ruff …
FernandezAstor Jun 22, 2026
2ee9632
Merge branch 'fix/windows-excel-export-error' into 'enterprise'
Jun 22, 2026
1f4a978
Merge remote-tracking branch 'origin/enterprise' into feat/TG-1094-mc…
Jun 22, 2026
1fe6947
refactor(mcp): apply TG-1094 review feedback
rboni-dk Jun 23, 2026
a75be88
Merge branch 'feat/TG-1094-mcp-monitors-lifecycle-and-settings' into …
Jun 23, 2026
3a5b1f2
fix(monitors): event-space SARIMAX for freshness-gated volume/metric …
aarthy-dk Jun 24, 2026
f60c55f
fix(TG-1113): show Managed Identity option on Synapse connection form
FernandezAstor Jun 24, 2026
99a56a2
Merge branch 'fix/TG-1113-synapse-managed-identity' into 'enterprise'
Jun 24, 2026
63164d9
Merge remote-tracking branch 'origin/enterprise' into fix/freshness-g…
Jun 24, 2026
5ef1537
:feat(test-definitions): faceted add-test picker dialog
luis-dk Jun 16, 2026
7b30bda
Merge branch 'feat/faceted-add-test-picker' into 'enterprise'
Jun 25, 2026
5f806d1
Merge remote-tracking branch 'origin/enterprise' into fix/freshness-g…
Jun 25, 2026
e208c6a
Merge branch 'fix/freshness-gated-volume-eventspace' into 'enterprise'
Jun 26, 2026
5a06c3a
feat(test-definitions): add external URL and custom metadata for clic…
aarthy-dk Jun 26, 2026
bdaa16a
fix(test-definitions): allow column_name on referential tests in vali…
aarthy-dk Jun 26, 2026
68ab291
refactor(test-definitions): address review feedback on click-through …
aarthy-dk Jun 26, 2026
13d6e74
refactor(test-definitions): split add/edit dialog into Parameters and…
aarthy-dk Jun 26, 2026
a66c85f
fix(test-definitions): restore field spacing in add/edit dialog tabs
aarthy-dk Jun 26, 2026
48fc2c3
fix(test-definitions): import Tooltip in Link and drop external-URL u…
aarthy-dk Jun 26, 2026
0fb9eef
Merge branch 'feat/TG-1134-external-url-custom-metadata' into 'enterp…
Jun 26, 2026
57cf36e
feat(oauth): personal access token schema and model
rboni-dk Jun 19, 2026
b2eb075
Merge branch 'feat/TG-1018-personal-access-token-and-token-mgmt-ui' i…
Jun 28, 2026
fbd021f
feat(mcp): add CRUD write tools for projects and test suites (TG-1070)
diogodk Jun 26, 2026
3a5bac8
refactor(mcp): lift render_diff_table + resolve_project to common (TG…
diogodk Jun 26, 2026
e5ec5c4
fix(mcp): minor tweaks to description and arg order
aarthy-dk Jun 29, 2026
8e3d36e
Merge branch 'feat/TG-1070-mcp-projects-suites-crud' into 'enterprise'
Jun 29, 2026
4cee4f6
feat(TG-1085): add data_classification tag field
FernandezAstor Jun 8, 2026
e473ec1
Merge branch 'feat/TG-1085-data-classification' into 'enterprise'
Jun 29, 2026
78d1c29
feat(mcp): add monitor L2 read tools — per-table events, configs, and…
diogodk Jun 25, 2026
c9de0cc
fix(mcp): align monitor L2 forecasts with the UI and harden the read …
aarthy-dk Jun 29, 2026
53310c5
fix(mcp): correct monitor forecast pagination, coupling parity, and n…
aarthy-dk Jun 29, 2026
e130f3c
Merge branch 'feat/TG-1092-mcp-monitors-l2' into 'enterprise'
Jun 29, 2026
73f00a4
feat(telemetry): async batched Mixpanel queue + MCP tool auto-instrum…
luis-dk Jun 18, 2026
d6920ae
Merge branch 'batched-telemetry' into 'enterprise'
Jun 30, 2026
bef5693
fix(monitors): keep gated forecast band continuous (no zero-width pinch)
aarthy-dk Jun 30, 2026
00e6efb
fix(data-catalog): bugs in editing tags
aarthy-dk Jun 30, 2026
d83af2f
fix(test definitions): display labels from test type yaml
aarthy-dk Jun 30, 2026
676d753
Merge branch 'qa-fixes' into 'enterprise'
Jun 30, 2026
2645433
fix(mcp): correct list_table_groups join, profiling-run PII counts, s…
aarthy-dk Jun 30, 2026
098ded0
test(mcp): update get_profiling_run test for count_for_run-based hygi…
aarthy-dk Jun 30, 2026
dfca707
Merge branch 'fix/TG-1135-mcp-qa-fixes' into 'enterprise'
Jun 30, 2026
0bbbd2e
release: 5.48.0 -> 5.70.2
aarthy-dk Jun 30, 2026
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ __pycache__/
work_area/
.envrc
environment.list
.claude/settings.local.json
.claude/repo.yml

# C extensions
*.so
Expand Down
9 changes: 3 additions & 6 deletions deploy/testgen-base.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ RUN apk update && apk upgrade && apk add --no-cache \
openblas=0.3.30-r2 \
openblas-dev=0.3.30-r2 \
unixodbc=2.3.14-r0 \
unixodbc-dev=2.3.14-r0 \
libarrow=21.0.0-r4 \
apache-arrow-dev=21.0.0-r4
unixodbc-dev=2.3.14-r0

COPY --chmod=775 ./deploy/install_linuxodbc.sh /tmp/dk/install_linuxodbc.sh
RUN /tmp/dk/install_linuxodbc.sh
Expand All @@ -39,7 +37,7 @@ COPY ./pyproject.toml /tmp/dk/pyproject.toml
RUN mkdir /dk

# Upgrading pip for security
RUN python3 -m pip install --no-cache-dir --upgrade pip==26.0
RUN python3 -m pip install --no-cache-dir --upgrade pip==26.1.2

# hdbcli only ships manylinux wheels (no musl). pip 26+ correctly rejects these on Alpine.
# We download the wheel for the correct arch, then extract it directly into site-packages
Expand Down Expand Up @@ -73,8 +71,7 @@ RUN apk del \
openssl \
linux-headers \
openblas-dev \
unixodbc-dev \
apache-arrow-dev
unixodbc-dev

# Remove interactive ODBC tools — not needed at runtime, and iusql triggers
# false-positive secret detection in security scanners (SECRET-3010)
Expand Down
2 changes: 1 addition & 1 deletion deploy/testgen.dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG TESTGEN_BASE_LABEL=v16
ARG TESTGEN_BASE_LABEL=v17

FROM datakitchen/dataops-testgen-base:${TESTGEN_BASE_LABEL} AS release-image

Expand Down
10 changes: 5 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "dataops-testgen"
version = "5.48.0"
version = "5.70.2"
description = "DataKitchen's Data Quality DataOps TestGen"
authors = [
{ "name" = "DataKitchen, Inc.", "email" = "info@datakitchen.io" },
Expand Down Expand Up @@ -61,7 +61,7 @@ dependencies = [
"xlsxwriter==3.2.0",
"psutil==5.9.8",
"concurrent_log_handler==0.9.25",
"cryptography==46.0.6",
"cryptography==48.0.1",
"validators==0.33.0",
"reportlab==4.2.2",
"cron-converter==1.2.1",
Expand All @@ -72,7 +72,7 @@ dependencies = [
"holidays~=0.89",

# Pinned to match the manually compiled libs or for security
"pyarrow==21.0.0",
"pyarrow==23.0.1",
"matplotlib==3.9.2",
"scipy==1.14.1",
"jinja2==3.1.6",
Expand All @@ -82,7 +82,7 @@ dependencies = [
# MCP server
"mcp[cli]==1.26.0",
"uvicorn==0.41.0",
"PyJWT==2.12.0",
"PyJWT==2.13.0",
"bcrypt==5.0.0",

# API & OAuth server
Expand Down Expand Up @@ -145,7 +145,7 @@ include-package-data = true
include = [
"testgen*",
]
exclude = [ "*.tests", "tests*", "deploy*", "invocations*", "testlib*"]
exclude = [ "*.tests", "tests*", "deploy*", "invocations*", "testgen.testing*"]

[tool.pytest.ini_options]
minversion = "7.0"
Expand Down
13 changes: 7 additions & 6 deletions testgen/api/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from sqlalchemy import select

from testgen.common.auth import authorize_token, decode_jwt_token
from testgen.common.auth import AuthError, authorize_token, decode_jwt_token
from testgen.common.enums import PublicJobKey
from testgen.common.models import Session, _current_session_wrapper, get_current_session
from testgen.common.models.job_execution import PUBLIC_JOB_KEYS, JobExecution
from testgen.common.models.job_execution import JobExecution
from testgen.common.models.project_membership import ProjectMembership
from testgen.common.models.table_group import TableGroup
from testgen.common.models.test_suite import TestSuite
Expand Down Expand Up @@ -47,7 +48,7 @@ def get_authorized_user(credentials: HTTPAuthorizationCredentials = _bearer_secu

try:
payload = decode_jwt_token(credentials.credentials)
except ValueError:
except AuthError:
raise _invalid from None

username = payload.get("username")
Expand All @@ -57,7 +58,7 @@ def get_authorized_user(credentials: HTTPAuthorizationCredentials = _bearer_secu
session = get_current_session()
try:
return authorize_token(credentials.credentials, username, session)
except ValueError:
except AuthError:
raise _invalid from None


Expand Down Expand Up @@ -122,15 +123,15 @@ def dependency(test_suite_id: UUID, user: User = _require_user) -> TestSuite:
def resolve_job(permission: str, *extra_filters):
"""Resolve a JobExecution by ``job_id`` path param and verify project permission.

Only jobs whose ``job_key`` is in ``PUBLIC_JOB_KEYS`` are exposed via the API.
Only externally-triggerable jobs (``PublicJobKey``) are exposed via the API.
Internal kinds (score rollups, recalculations, monitor runs) are filtered out
by construction. Extra ORM clauses are appended to the WHERE clause to further
restrict by job_key when a caller wants a single kind.
"""
def dependency(job_id: UUID, user: User = _require_user) -> JobExecution:
query = select(JobExecution).where(
JobExecution.id == job_id,
JobExecution.job_key.in_(PUBLIC_JOB_KEYS),
JobExecution.job_key.in_(list(PublicJobKey)),
*extra_filters,
)
return _check_access(get_current_session().scalars(query).first(), user, permission)
Expand Down
52 changes: 52 additions & 0 deletions testgen/api/enums.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Lowercase presentation enums for API v1 request filters and responses.

Shared home for StrEnums that map a DB-stored value to the lowercase snake_case
form exposed through the API. Several DB columns store title-case values
(``test_results.result_status``, ``*.disposition``); the mapping dicts here are the
single seam that normalizes them to the API surface — the DB is never changed.
"""

from enum import StrEnum

from testgen.common.enums import Disposition as DbDisposition
from testgen.common.models.test_result import TestResultStatus


class ResultStatus(StrEnum):
"""Outcome of a single test result."""

passed = "passed"
failed = "failed"
warning = "warning"
error = "error"
log = "log"


class Disposition(StrEnum):
"""Triage state of a test result. ``no_decision`` is the state of a result no one
has triaged yet. Omitting the filter returns active results (``confirmed`` and
``no_decision``); pass an explicit value to filter to a single state."""

confirmed = "confirmed"
dismissed = "dismissed"
muted = "muted"
no_decision = "no_decision"


RESULT_STATUS_TO_DB: dict[ResultStatus, TestResultStatus] = {
ResultStatus.passed: TestResultStatus.Passed,
ResultStatus.failed: TestResultStatus.Failed,
ResultStatus.warning: TestResultStatus.Warning,
ResultStatus.error: TestResultStatus.Error,
ResultStatus.log: TestResultStatus.Log,
}
RESULT_STATUS_FROM_DB: dict[TestResultStatus, ResultStatus] = {v: k for k, v in RESULT_STATUS_TO_DB.items()}

# ``no_decision`` has no stored DB value — it corresponds to a NULL ``disposition``
# column, handled explicitly at the API boundary (not present in these dicts).
DISPOSITION_TO_DB: dict[Disposition, DbDisposition] = {
Disposition.confirmed: DbDisposition.CONFIRMED,
Disposition.dismissed: DbDisposition.DISMISSED,
Disposition.muted: DbDisposition.INACTIVE,
}
DISPOSITION_FROM_DB: dict[DbDisposition, Disposition] = {v: k for k, v in DISPOSITION_TO_DB.items()}
8 changes: 4 additions & 4 deletions testgen/api/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
resolve_test_suite,
)
from testgen.api.schemas import ErrorResponse, JobListResponse, JobResponse, JobSubmittedResponse
from testgen.common.enums import JobKey, JobSource, JobStatus
from testgen.common.models.job_execution import PUBLIC_JOB_KEYS, JobExecution
from testgen.common.enums import JobKey, JobSource, JobStatus, PublicJobKey
from testgen.common.models.job_execution import JobExecution
from testgen.common.models.table_group import TableGroup
from testgen.common.models.test_suite import TestSuite

Expand Down Expand Up @@ -98,15 +98,15 @@ def cancel_job(job: JobExecution = resolve_job("edit")): # noqa: B008
)
def list_jobs(
project_code: str = resolve_project_code("view"),
job_key: JobKey | None = Query(default=None), # noqa: B008
job_key: PublicJobKey | None = Query(default=None), # noqa: B008
status: JobStatus | None = Query(default=None), # noqa: B008
page: int = Query(default=1, ge=1),
limit: int = Query(default=20, ge=1, le=100),
):
"""List job executions for a project, with optional filters and pagination."""
items, total = JobExecution.list_for_project(
project_code,
JobExecution.job_key.in_(PUBLIC_JOB_KEYS),
JobExecution.job_key.in_(list(PublicJobKey)),
job_key=job_key,
status=status,
page=page,
Expand Down
2 changes: 1 addition & 1 deletion testgen/api/oauth/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
def authorization_server_metadata():
"""Return OAuth 2.1 Authorization Server Metadata per RFC 8414.

MCP clients use this for server discovery.
OAuth clients use this for server discovery.
"""
base_url = settings.BASE_URL.rstrip("/")

Expand Down
45 changes: 0 additions & 45 deletions testgen/api/oauth/models.py

This file was deleted.

2 changes: 1 addition & 1 deletion testgen/api/oauth/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
from testgen import settings
from testgen.api.deps import db_session
from testgen.api.oauth.login import render_login_page
from testgen.api.oauth.models import OAuth2Client
from testgen.api.oauth.server import TestGenAuthorizationServer
from testgen.common.auth import create_jwt_token, decode_jwt_token, verify_password
from testgen.common.models import get_current_session
from testgen.common.models.oauth import OAuth2Client
from testgen.common.models.user import User

LOG = logging.getLogger("testgen")
Expand Down
23 changes: 1 addition & 22 deletions testgen/api/oauth/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

Grant types:
- Authorization Code + PKCE (for MCP clients)
- Client Credentials (for automation scripts)
- Refresh Token (for token renewal)

All DB operations use get_current_session() for thread-local session access.
Expand All @@ -13,15 +12,14 @@
from typing import ClassVar

from authlib.oauth2.rfc6749 import AuthorizationServer, JsonRequest, OAuth2Request, grants
from authlib.oauth2.rfc6749.errors import InvalidGrantError
from authlib.oauth2.rfc7009 import RevocationEndpoint
from authlib.oauth2.rfc7636 import CodeChallenge
from sqlalchemy import select

from testgen import settings
from testgen.api.oauth.models import OAuth2AuthorizationCode, OAuth2Client, OAuth2Token
from testgen.common.auth import create_jwt_token
from testgen.common.models import get_current_session
from testgen.common.models.oauth import OAuth2AuthorizationCode, OAuth2Client, OAuth2Token
from testgen.common.models.user import User


Expand Down Expand Up @@ -85,24 +83,6 @@ def revoke_old_credential(self, credential):
credential.access_token_revoked_at = int(time.time())


class ClientCredentialsGrant(grants.ClientCredentialsGrant):
"""Client credentials grant that resolves the client's owner as the token user.

Ensures every token has a real User identity — no "ghost" usernames.
"""

def validate_token_request(self):
super().validate_token_request()
client = self.request.client
if not client.user_id:
raise InvalidGrantError(description="Client has no registered owner.")
session = get_current_session()
owner = session.scalars(select(User).where(User.id == client.user_id)).first()
if owner is None:
raise InvalidGrantError(description="Client owner no longer exists.")
self.request.user = owner


class TestGenRevocationEndpoint(RevocationEndpoint):
def query_token(self, token_string, token_type_hint):
session = get_current_session()
Expand Down Expand Up @@ -183,7 +163,6 @@ def create_authorization_server() -> TestGenAuthorizationServer:
"""Create and configure the authorization server with all grant types."""
server = TestGenAuthorizationServer()
server.register_grant(AuthorizationCodeGrant, [CodeChallenge(required=True)])
server.register_grant(ClientCredentialsGrant)
server.register_grant(RefreshTokenGrant)
server.register_endpoint(TestGenRevocationEndpoint)
server.register_token_generator("default", _generate_bearer_token)
Expand Down
Loading
Loading