Skip to content

feat(api): enforce explicit v1 negotiation contract - #379

Closed
seonghobae wants to merge 7 commits into
mainfrom
feat/api-version-negotiation-main-20260811
Closed

feat(api): enforce explicit v1 negotiation contract#379
seonghobae wants to merge 7 commits into
mainfrom
feat/api-version-negotiation-main-20260811

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Objective

Advance issue #315 with a bounded HTTP version-negotiation boundary. Existing /api/v1/** clients remain backward compatible when no version header is sent, while an explicitly unsupported or contradictory requested version fails closed before controller dispatch and every API response identifies the current v1 contract.

Exact current-head evidence

  • protected base at latest head construction: 961f44a19c4ced87f8062b3ab9842a9a08d05235;
  • exact head: 7b98171aff415f05e31df0de37e230f9d39d0758;
  • changed paths: ApiVersionWebFilter.java and its focused regression only;
  • CI, Security Scan, SAST Semgrep, and fuzz: terminal-success;
  • mergeable: true;
  • unresolved inline findings: zero.

Version contract

Non-API paths bypass negotiation. Missing or blank version headers preserve v1 compatibility. Explicit v1 is accepted. Every API response advertises X-Clearfolio-Api-Version: v1. Unsupported or conflicting version requests return a controlled JSON 400 before downstream dispatch.

Scope boundary

Version-negotiation filter only. This does not complete OpenAPI/schema parity, breaking-change detection, generated clients, naruon consumer compatibility, or release schema provenance. Issue #315 remains open for those guarantees.

Merge gate

Keep this exact head unchanged. Auto-merge may act only after live required checks remain terminal-success, zero valid unresolved findings remain, and a qualifying independent non-author approval is attached to this exact head. Any head/base movement requires complete exact-head revalidation; predecessor evidence does not transfer.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review available on request

  • 🔍 Trigger review

Reviews should be triggered manually for repositories with fewer than 10 stars. Select Trigger review above or comment @coderabbitai review to review the latest changes. For a full review, comment @coderabbitai full review.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1e3ee2ed-1101-48a4-a5fe-28ead919c1d4

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2718d9c9-78ef-4ee1-8161-c00c3d41ecb5

📥 Commits

Reviewing files that changed from the base of the PR and between 961f44a and 7b98171.

📒 Files selected for processing (2)
  • src/main/java/com/clearfolio/viewer/config/ApiVersionWebFilter.java
  • src/test/java/com/clearfolio/viewer/config/ApiVersionWebFilterTest.java

📝 Walkthrough

Walkthrough

ApiVersionWebFilter가 API 요청의 버전 헤더를 검증한다. 지원 버전은 체인으로 전달하고 현재 버전 응답 헤더를 설정한다. 지원되지 않는 버전은 400 JSON 오류로 거부한다. 테스트가 주요 경로를 검증한다.

Changes

API 버전 협상

Layer / File(s) Summary
버전 필터 계약과 처리 흐름
src/main/java/com/clearfolio/viewer/config/ApiVersionWebFilter.java
ApiVersionWebFilter/api/ 요청의 버전 헤더를 검증한다. 헤더가 없거나 비어 있거나 v1이면 요청을 전달한다. 다른 버전이나 충돌하는 중복 버전은 400 JSON 응답으로 종료한다.
버전 협상 동작 검증
src/test/java/com/clearfolio/viewer/config/ApiVersionWebFilterTest.java
비 API 요청 우회, 기본 버전 처리, 현재 버전 처리, 공백 헤더 처리, 중복 버전 거부 및 오류 응답 본문을 검증한다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Mergeability Score: 🔵 Low · up to 7b981

The new API version-negotiation behavior may be skipped when an earlier request filter ends processing, allowing unsupported versions through or omitting the response version header. The PR is mergeable with explicit owner awareness and follow-up to define ordering and add full-chain coverage.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ApiVersionWebFilter
  participant WebFilterChain
  Client->>ApiVersionWebFilter: API 요청과 버전 헤더 전달
  ApiVersionWebFilter->>ApiVersionWebFilter: 버전 헤더 검증
  alt 헤더 없음, 빈 값 또는 v1
    ApiVersionWebFilter->>WebFilterChain: 요청 전달
    WebFilterChain-->>Client: 현재 버전 응답 헤더와 처리 결과
  else 지원되지 않는 버전
    ApiVersionWebFilter-->>Client: 400 JSON 오류 응답
  end
Loading

Possibly related PRs

  • ContextualWisdomLab/clearfolio#381: 런타임 API 버전 협상 범위와 v1 호환성 측면에서 관련되지만, 다른 코드와 OpenAPI 호환성 검사기를 다룬다.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 API의 명시적 v1 버전 협상 강제를 정확하고 간결하게 설명하며 PR의 주요 변경 사항과 일치합니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/api-version-negotiation-main-20260811

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.

@seonghobae
seonghobae marked this pull request as ready for review August 11, 2026 06:20
@seonghobae
seonghobae enabled auto-merge (squash) August 11, 2026 06:21

Copy link
Copy Markdown
Collaborator Author

@opencode-agent review
@coderabbitai review
@cwl-noema-review review
@strix review

Review exact head 7b98171aff415f05e31df0de37e230f9d39d0758 only. Exact-head CI, Security Scan, SAST Semgrep, and fuzz are terminal-success; unresolved inline findings are zero. Validate non-API bypass, backward-compatible absent/blank version handling, explicit v1 acceptance, controlled conflicting/unsupported rejection before dispatch, and response-version disclosure.

Review read-only; preserve independent reviewer identity. Do not mutate the branch, synthesize author approval, weaken protection, or merge.

@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

expected='7b98171aff415f05e31df0de37e230f9d39d0758'
actual="$(git rev-parse HEAD)"
printf 'HEAD=%s\nEXPECTED=%s\n' "$actual" "$expected"
if [ "$actual" != "$expected" ]; then
  echo 'ERROR: The checked-out revision does not match the requested head.' >&2
  exit 2
fi

echo '--- Changed files at exact head ---'
git diff-tree --no-commit-id --name-status -r "$expected"

echo '--- Exact-head diff ---'
git diff "${expected}^" "$expected" -- \
  src/main/java/com/clearfolio/viewer/config/ApiVersionWebFilter.java \
  src/test/java/com/clearfolio/viewer/config/ApiVersionWebFilterTest.java

echo '--- Filter outline ---'
ast-grep outline src/main/java/com/clearfolio/viewer/config/ApiVersionWebFilter.java \
  --items all --view expanded

echo '--- Filter source ---'
cat -n src/main/java/com/clearfolio/viewer/config/ApiVersionWebFilter.java

echo '--- Filter test outline ---'
ast-grep outline src/test/java/com/clearfolio/viewer/config/ApiVersionWebFilterTest.java \
  --items all --view expanded

echo '--- Filter test source ---'
cat -n src/test/java/com/clearfolio/viewer/config/ApiVersionWebFilterTest.java

echo '--- Filter registration, ordering, and API path references ---'
rg -n -C 4 --glob '*.java' \
  '(ApiVersionWebFilter|WebFilter\b|`@Order`\b|/api/v1|/api/)' src/main/java

echo '--- Exact-head GitHub checks ---'
gh api "repos/ContextualWisdomLab/clearfolio/commits/${expected}/check-runs?per_page=100" \
  --jq '.check_runs[] | [.name, .status, .conclusion] | `@tsv`' || true

echo '--- Exact-head GitHub status contexts ---'
gh api "repos/ContextualWisdomLab/clearfolio/commits/${expected}/status" \
  --jq '.statuses[] | [.context, .state] | `@tsv`' || true

Length of output: 41270


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo='ContextualWisdomLab/clearfolio'
pr='379'
head='7b98171aff415f05e31df0de37e230f9d39d0758'

echo '--- Pull request metadata ---'
gh pr view "$pr" --repo "$repo" \
  --json baseRefName,baseRefOid,headRefName,headRefOid,mergeStateStatus,reviewDecision \
  --jq '{baseRefName, baseRefOid, headRefName, headRefOid, mergeStateStatus, reviewDecision}'

base="$(gh pr view "$pr" --repo "$repo" --json baseRefOid --jq '.baseRefOid')"
merge_base="$(git merge-base "$base" "$head")"
printf '%s\n' "--- Merge base ---" "BASE=$base" "MERGE_BASE=$merge_base"

echo '--- Cumulative pull request files ---'
git diff --name-status "$merge_base" "$head"

echo '--- Cumulative pull request diff ---'
git diff --find-renames --find-copies "$merge_base" "$head" -- \
  src/main/java/com/clearfolio/viewer/config/ApiVersionWebFilter.java \
  src/test/java/com/clearfolio/viewer/config/ApiVersionWebFilterTest.java

echo '--- All request mapping declarations ---'
rg -n -C 2 --glob '*.java' \
  '@(?:Get|Post|Put|Patch|Delete|Request)Mapping\(' src/main/java

echo '--- Existing API error codes and response-body construction ---'
rg -n -C 5 --glob '*.java' \
  '(errorCode|traceId|supportedVersion|setStatusCode\(|writeWith\(|ErrorResponse|ExceptionHandler|ResponseStatusException)' \
  src/main/java

echo '--- Filter and exception-handler ordering declarations ---'
rg -n -C 5 --glob '*.java' \
  '(`@Order`\b|Ordered\b|implements WebFilter|WebFilterRegistrationBean|WebExceptionHandler)' \
  src/main/java

echo '--- Complete security-header filter for chain behavior ---'
cat -n src/main/java/com/clearfolio/viewer/config/ViewerSecurityHeadersWebFilter.java

Length of output: 110470


@seonghobae Reviewed exact head 7b98171aff415f05e31df0de37e230f9d39d0758.

I found no blocking issues.

The implementation meets the requested behavior:

  • Non-API paths bypass version negotiation.
  • Missing and blank version headers preserve the v1 contract.
  • An explicit v1 header is accepted.
  • Duplicate or unsupported version headers return 400 Bad Request before the remaining filter chain runs.
  • API responses include X-Clearfolio-Api-Version: v1.
  • The rejection body uses the established API error-envelope fields and does not disclose the unsupported request value.

The cumulative PR diff contains only the new filter and focused tests. The exact-head Maven test, security scans, SAST checks, and listed fuzz checks succeeded.

⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@opencode-agent

Copy link
Copy Markdown
Contributor

Queued @opencode-agent ; Already queued @cwl-noema-review on this exact request for PR #379 at head e81a55aa25419ee35b5eadf37f347bde756d9667. Central exact-name Actions artifacts are the durable dispatch ledger; existing review workflows remain authoritative for the final verdict and failure evidence.

@opencode-agent
opencode-agent Bot disabled auto-merge August 19, 2026 10:44
@opencode-agent

Copy link
Copy Markdown
Contributor

Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #379 at head e81a55aa25419ee35b5eadf37f347bde756d9667. Central exact-name Actions artifacts are the durable dispatch ledger; existing review workflows remain authoritative for the final verdict and failure evidence.

6 similar comments
@opencode-agent

Copy link
Copy Markdown
Contributor

Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #379 at head e81a55aa25419ee35b5eadf37f347bde756d9667. Central exact-name Actions artifacts are the durable dispatch ledger; existing review workflows remain authoritative for the final verdict and failure evidence.

@opencode-agent

Copy link
Copy Markdown
Contributor

Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #379 at head e81a55aa25419ee35b5eadf37f347bde756d9667. Central exact-name Actions artifacts are the durable dispatch ledger; existing review workflows remain authoritative for the final verdict and failure evidence.

@opencode-agent

Copy link
Copy Markdown
Contributor

Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #379 at head e81a55aa25419ee35b5eadf37f347bde756d9667. Central exact-name Actions artifacts are the durable dispatch ledger; existing review workflows remain authoritative for the final verdict and failure evidence.

@opencode-agent

Copy link
Copy Markdown
Contributor

Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #379 at head e81a55aa25419ee35b5eadf37f347bde756d9667. Central exact-name Actions artifacts are the durable dispatch ledger; existing review workflows remain authoritative for the final verdict and failure evidence.

@opencode-agent

Copy link
Copy Markdown
Contributor

Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #379 at head e81a55aa25419ee35b5eadf37f347bde756d9667. Central exact-name Actions artifacts are the durable dispatch ledger; existing review workflows remain authoritative for the final verdict and failure evidence.

@opencode-agent

Copy link
Copy Markdown
Contributor

Already queued @cwl-noema-review and @opencode-agent on this exact request for PR #379 at head e81a55aa25419ee35b5eadf37f347bde756d9667. Central exact-name Actions artifacts are the durable dispatch ledger; existing review workflows remain authoritative for the final verdict and failure evidence.

Copy link
Copy Markdown
Collaborator Author

Closing as superseded by consolidated current-main Draft #488. #488 preserves this PR's exact runtime version-filter production/test blobs and places negotiation on the same authority line as operation identity, compatibility, provenance, and tagged release acceptance. Previous checks/reviews remain provenance only.

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.

1 participant