feat(api): probe a provider with the request's key and keep nothing - #1056
Conversation
1ee3544 to
8e0a2a8
Compare
yeongseon
left a comment
There was a problem hiding this comment.
diff 전체(라우트 → ProvidersService.probe_provider → provider_probe.run_probe, 계약, 테스트)를 읽었습니다. 설계에는 동의하고, 머지 전에 고칠 것이 하나 있습니다.
고칠 것 — 머지하면 main 의 Cross-repo contract 가 빨개집니다
이 브랜치에서 그 워크플로를 수동 실행했습니다 (run 37419757613 → failure):
FAILED test_provider_key_probe.py::test_the_real_client_calls_with_the_header_key_and_not_the_operators - assert 0 == 1
FAILED test_provider_key_probe.py::test_the_key_reaches_no_response_and_no_log_when_the_upstream_echoes_it[401] - assert 'available' != 'available'
FAILED ...[403]
FAILED ...[500]
그 잡은 KPUBDATA_MODE=replay / KPUBDATA_REPLAY_DIR 을 줍니다. 그러면 kpubdata 가 HTTP 대신 기록된 fixture 를 재생해서, upstream fixture 가 바꿔 끼운 httpx.Client 에 요청이 닿지 않습니다(요청 0건, 상태는 늘 available). 경로 필터 때문에 이 PR 의 CI 에서는 그 워크플로가 돌지 않습니다. #1051 에서 같은 일이 있었고 #1052 로 고쳤습니다 — 제가 그때 놓친 것이라 이번에는 먼저 돌려 봤습니다.
upstream fixture 에서 지우면 됩니다 (test_credential_hosts.py, test_canary_leak_gate.py, test_operator_key_never_leaves.py 와 같은 방식):
# The cross-repo job replays recorded fixtures instead of calling HTTP; these tests
# need the HTTP path they observe.
monkeypatch.delenv("KPUBDATA_REPLAY_DIR", raising=False)
monkeypatch.delenv("KPUBDATA_MODE", raising=False)고친 뒤 gh workflow run cross-repo-contract.yml --ref feat/issue-802-provider-key-probe 로 확인해 주세요. 제가 다시 돌려 봐도 됩니다.
물으신 것
- 경로 이름·응답 모양: 그대로 갑니다.
status를 enum 으로 두지 않은 것도 맞습니다 — kpubdata 가 상태를 더할 수 있고, Studio #764 가 문자열로 받습니다. - 45초·순차: 그대로 갑니다. 사용자 키로 provider 에 동시 호출을 내지 않는 쪽이 맞습니다.
- 결과를 계정에 저장: 이번에는 하지 않습니다. kpubdata#812 가 서버 쪽 보관을 미룬 것과 같은 선입니다. 응답에 키에서 유도한 값이 없으므로 Studio 가 필요하면 자기 쪽에서 보관합니다.
Closes #802는 이 결정을 근거로 유지합니다.
알아 둘 것 (막지 않음)
- 호출량 한도가 없습니다. 인증된 사용자 누구나 한 요청으로 서버가 provider 에 최대 25건(datago 22 + localdata 3 기준)을 내게 할 수 있고, 반복하면 그 호출은 모두 서버의 IP 에서 나갑니다. 아무 문자열이나 키로 넣어도 나갑니다. provider 가 IP 단위로 막으면 다른 사용자 전체가 영향을 받습니다. 다중 사용자 배포 전에 사용자별 probe 간격이나 동시 1건 제한이 필요합니다 — 이슈로 올려 주세요.
- replay 모드의 Builder 는 어떤 키에도
available을 답합니다(위 실패가 보여 준 것). 데모·개발용이라 동작은 맞지만, 계약 설명이나 문서에 한 줄 있으면 좋겠습니다. - 502 응답에
code가 없습니다. 기존 provider 라우트의 502 와 같은 모양이라 이 PR 에서 바꿀 것은 아닙니다.
순서
Studio #764 (스키마) 가 먼저 머지된 것을 확인했습니다. 이 PR 이 머지되면 Studio main 의 drift 를 다시 돌려 확인하겠습니다.
POST /providers/{provider}/probe answers, per spec-defined dataset, with
kpubdata's probe status and the provider service it belongs to. Only the
key in the X-Provider-Key header is used: the client is built with that
key and env_keys=False, so neither a stored credential nor the operator's
environment key is tried. Nothing is stored, and the response and logs
hold nothing of the key. A 45 s budget bounds a request against a
provider that is down.
Contract 1.87.0 (additive).
Closes #802
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The cross-repo job sets KPUBDATA_MODE=replay, so kpubdata replays recorded fixtures and the mocked HTTP layer sees no request. Remove the replay settings in the upstream fixture, and say in the contract that a replay-mode Builder answers available for any key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8e0a2a8 to
a77f429
Compare
|
고쳤습니다 (
502 의 경로 필터 때문에 PR CI 에서 그 워크플로가 돌지 않는다는 점은 제가 놓쳤습니다. 실제 kpubdata |
yeongseon
left a comment
There was a problem hiding this comment.
a77f429 를 확인하고 승인합니다.
upstreamfixture 가KPUBDATA_REPLAY_DIR·KPUBDATA_MODE를 지웁니다.- 이 head 에서
Cross-repo contract수동 실행이 run 37421312435 →success인 것을 제가 다시 조회해 확인했습니다 (고치기 전8e0a2a8은 run 37419757613 →failure). - replay 모드 한 줄이 계약 설명에 들어갔고, 호출량 한도는 #1059 로 올라갔습니다.
CI 가 끝나면 머지하고, Studio main 의 drift 를 확인하겠습니다.
무엇을
#802 —
POST /providers/{provider}/probe. 요청의X-Provider-Key헤더에 실린 키로, 그 provider 의 데이터셋마다 kpubdataPROBE_STATUSES(available / application_required / params_invalid …)와 소속 서비스(service_id)를 돌려줍니다. 계약 1.87.0 (additive).kpubdata 0.9.0 이
Client.probe와env_keys=False를 공개 API 로 내면서(#1050 에서 pin) 막혀 있던 것이 풀렸습니다.동작
Client(provider_keys={provider: key}, cache=False, env_keys=False)로 만듭니다. 저장된 credential 이나 서버 환경변수의 키는 배포 모드와 무관하게 쓰지 않습니다. 헤더에 그 provider 의 키가 없으면 400provider_key_required.datasets로 좁힐 수 있습니다(최대 50).not_probed에 적고complete: false로 답합니다. 관찰하지 않은 것에 상태를 붙이지 않습니다.범위 대조 (이슈 체크리스트)
POST /providers/{provider}/probe, 키는 헤더로만, 요청이 끝나면 버림PROBE_STATUSES어휘 그대로 +service_idGET /providers의last_test처럼) 후속으로 하겠습니다 — 결정이 필요합니다.test_canary_leak_gate.py) 본체에 이 경로를 넣지는 않았고, 같은 방식(실제 kpubdataClient+httpx.MockTransport)의 테스트를 이 파일에 뒀습니다.테스트 (
tests/unit/test_provider_key_probe.py, 19건)Client: 업스트림에 간 요청에 헤더의 키가 있고 운영자 키는 없음Client: 업스트림이 401/403/500 으로 요청 URL(키 포함)을 되돌려 줘도 응답과 DEBUG 로그에 키 없음Client: 다른 provider 로 연 probe 는 환경변수 키로 내려가지 않고auth_unknown, 호출 0건probe unavailable(예외 문구 미노출)머지 순서
kpubdata-studio#764 를 먼저 머지해야 했고, 머지됐습니다(스키마만 추가). 이 PR 은 200 응답 예시를 더하는데, Studio 의 drift 검사는 Builder
main의 모든 예시에 Studio 스키마를 요구합니다(스키마 없이 돌리면 1건 실패하는 것을 확인했습니다). 새 named error 예시는 넣지 않았습니다.정해 주셨으면 하는 것
/probe, 이슈의 제안 그대로)과 응답 모양.status를 계약에서 enum 으로 두지 않았습니다(kpubdata 가 상태를 더할 수 있어서).검증
ruff check,ruff format,mypy src통과scripts/check_contract_compat.py --base origin/main→compatible: 1.86.0 -> 1.87.0pytest tests/unit -x종료 코드 0, 실패 없음 (스킵 8건은 기존 것)Closes #802
🤖 Generated with Claude Code