Skip to content

fix(security): authenticate artifact tokens before object lookup on current main - #431

Open
seonghobae wants to merge 6 commits into
mainfrom
fix/artifact-token-precondition-main-20260813-r2
Open

fix(security): authenticate artifact tokens before object lookup on current main#431
seonghobae wants to merge 6 commits into
mainfrom
fix/artifact-token-precondition-main-20260813-r2

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Objective

Authenticate public artifact-read tokens before conversion-job or artifact-store lookup so token validity cannot become a document-existence oracle.

Exact current-head evidence

  • protected base: 961f44a19c4ced87f8062b3ab9842a9a08d05235;
  • test-only RED head: cd5a8a965dfefbe81c131d60748d7311dda858bd;
  • exact GREEN head: 2f16af873714e62870d059324f9fe0bdead29874;
  • CI, Security Scan, SAST Semgrep, and fuzz: terminal-success;
  • mergeable: true;
  • all inline review threads: resolved.

Contract

Missing credentials, unsupported Authorization schemes, non-empty invalid query tokens, and invalid Bearer tokens return 401 before any conversion-job or artifact-store interaction. The preauthorization phase verifies syntax, signature, lifetime, read scope, document binding, issued-link authority, and revocation state without object lookup. Full tenant and artifact-checksum binding remains mandatory after lookup and before bytes are returned.

Credential-source dependency

The existing Spring-placeholder secret source is unchanged from protected main; its provider-neutral KV/credential-registry migration is explicitly owned by #319 with rotation, restart/replica, least-privilege, no-secret-telemetry, and standalone/composed adapter acceptance. This PR does not claim that the current source is commercially final and must not duplicate or race #319's architecture.

Scope boundary

Artifact-read preauthorization and focused regressions only. Parser hardening, checksum/tenant binding, range semantics, read audit, and signed-link behavior are preserved.

Merge gate

Keep this exact head unchanged. Auto-merge may act only after live checks remain successful, zero valid unresolved findings remain, and a qualifying independent non-author approval is attached to this exact head. Automated evidence and predecessor reviews do not transfer.

@coderabbitai

coderabbitai Bot commented Aug 13, 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: 017946cb-7a99-490e-b5f0-53e006155845

📝 Walkthrough

Walkthrough

PDF 조회 전에 읽기 토큰을 사전 검증하도록 변경했습니다. 토큰 오류는 문서 변환 및 아티팩트 조회 전에 반환합니다. 테넌트와 체크섬 검증은 최종 검증 단계에서 유지합니다.

Changes

아티팩트 토큰 접근 제어

Layer / File(s) Summary
토큰 사전 검증 계약
src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java
토큰 형식, 서명, 만료, 스코프, 문서 ID, 발급 원장 및 폐기 상태 검증을 preauthorizeReadToken으로 분리했습니다. verifyReadToken은 이 메서드를 호출한 뒤 테넌트와 체크섬을 검증합니다.
PDF 조회 사전조건 흐름
src/main/java/com/clearfolio/viewer/controller/ArtifactController.java
PDF 조회 전에 토큰을 해석하고 사전 승인합니다. 토큰 오류가 발생하면 즉시 오류 응답을 반환합니다.
접근 검증 테스트
src/test/java/com/clearfolio/viewer/controller/ArtifactControllerTokenPreconditionTest.java, src/test/java/com/clearfolio/viewer/controller/ArtifactControllerPostLookupBindingTest.java, src/test/java/com/clearfolio/viewer/controller/ArtifactControllerTest.java
누락·지원되지 않는 방식·잘못된 쿼리 및 Bearer 토큰을 401 UNAUTHORIZED로 검증합니다. 사후 테넌트 불일치를 403 Forbidden으로 검증합니다. 기존 PDF 테스트는 서명된 artifact URL을 사용합니다.

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

Mergeability Score: 🟡 Moderate · up to 2f16a

This PR changes artifact-token authentication while retaining secret injection through a Spring environment placeholder, conflicting with the required credential-registry handling and leaving a security configuration risk unresolved; merge should wait for migration or explicit owner acceptance.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ArtifactController
  participant ArtifactLinkService
  participant DocumentConversionService
  participant ArtifactStore
  Client->>ArtifactController: PDF 요청 및 토큰 전달
  ArtifactController->>ArtifactLinkService: preauthorizeReadToken(docId, token)
  ArtifactLinkService-->>ArtifactController: 토큰 클레임 또는 토큰 오류
  ArtifactController->>DocumentConversionService: 문서 및 작업 조회
  ArtifactController->>ArtifactStore: PDF 아티팩트 조회
  ArtifactController->>ArtifactLinkService: verifyReadToken(docId, token, 작업, 체크섬)
  ArtifactLinkService-->>ArtifactController: 최종 검증 결과
  ArtifactController-->>Client: PDF 또는 오류 응답
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 제목은 아티팩트 토큰을 객체 조회 전에 인증하는 주요 변경 사항을 정확하고 간결하게 설명합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/artifact-token-precondition-main-20260813-r2

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 13, 2026 03:03
@seonghobae
seonghobae enabled auto-merge (squash) August 13, 2026 03:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java`:
- Around line 186-199: ArtifactLinkService still sources the artifact-token
secret through a Spring `@Value` environment placeholder. Replace that injection
with the project’s credential registry or KV-based secret provider, remove the
placeholder dependency, and update the service’s token-authentication
initialization to use the registry-provided value while preserving existing
artifact-token and tenant-claims validation behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4fafca6a-6dae-45c3-a606-bf078e53f378

📥 Commits

Reviewing files that changed from the base of the PR and between 961f44a and 2f16af8.

📒 Files selected for processing (5)
  • src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java
  • src/main/java/com/clearfolio/viewer/controller/ArtifactController.java
  • src/test/java/com/clearfolio/viewer/controller/ArtifactControllerPostLookupBindingTest.java
  • src/test/java/com/clearfolio/viewer/controller/ArtifactControllerTest.java
  • src/test/java/com/clearfolio/viewer/controller/ArtifactControllerTokenPreconditionTest.java

@opencode-agent
opencode-agent Bot disabled auto-merge August 13, 2026 03:46
@seonghobae
seonghobae enabled auto-merge (squash) August 14, 2026 08:47

Copy link
Copy Markdown
Collaborator Author

Exact-current-head read-only review request for 2f16af873714e62870d059324f9fe0bdead29874 on protected main 961f44a19c4ced87f8062b3ab9842a9a08d05235. CI, Security Scan, SAST Semgrep, and fuzz are terminal-success; the five-file token-preauthorization repair is mergeable and all inline threads are resolved. Verify that invalid or absent credentials fail before every job/store lookup, while final tenant/checksum binding remains mandatory. Credential-source migration remains explicitly owned by #319. Do not mutate the branch or bypass independent approval.

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

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown

Rate Limit Exceeded

@seonghobae have exceeded the limit for the number of chat messages per hour. Please wait 46 minutes and 22 seconds before sending another message.

Copy link
Copy Markdown
Collaborator Author

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

Review exact head 2f16af873714e62870d059324f9fe0bdead29874 only. Exact-head CI, Security Scan, SAST Semgrep, and fuzz are terminal-success and the existing inline findings are resolved. Confirm that invalid or missing artifact credentials fail before job/store lookup while checksum and tenant binding remain enforced after lookup.

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='2f16af873714e62870d059324f9fe0bdead29874'
actual="$(git rev-parse HEAD)"
printf 'HEAD=%s\nEXPECTED=%s\n' "$actual" "$expected"
if [ "$actual" != "$expected" ]; then
  echo 'ERROR: repository HEAD is not the requested commit.' >&2
  exit 2
fi

for f in \
  src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java \
  src/main/java/com/clearfolio/viewer/controller/ArtifactController.java \
  src/test/java/com/clearfolio/viewer/controller/ArtifactControllerTokenPreconditionTest.java \
  src/test/java/com/clearfolio/viewer/controller/ArtifactControllerPostLookupBindingTest.java \
  src/test/java/com/clearfolio/viewer/controller/ArtifactControllerTest.java
do
  test -f "$f"
  printf '\n===== OUTLINE: %s =====\n' "$f"
  ast-grep outline "$f" --view expanded || true
done

printf '\n===== AUTHORIZATION, LOOKUP, AND BINDING CALL SITES =====\n'
rg -n -C 8 --type java \
  '(preauthorizeReadToken|verifyReadToken|conversionService|artifactStore|findBy|load|tenant|checksum)' \
  src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java \
  src/main/java/com/clearfolio/viewer/controller/ArtifactController.java

printf '\n===== FOCUSED TEST ASSERTIONS =====\n'
rg -n -C 6 --type java \
  '(UNAUTHORIZED|FORBIDDEN|never\(|verify\(|preauthorizeReadToken|verifyReadToken|checksum|tenant|artifact)' \
  src/test/java/com/clearfolio/viewer/controller/ArtifactControllerTokenPreconditionTest.java \
  src/test/java/com/clearfolio/viewer/controller/ArtifactControllerPostLookupBindingTest.java \
  src/test/java/com/clearfolio/viewer/controller/ArtifactControllerTest.java

Length of output: 142735


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '===== ArtifactController.getPdf ====='
sed -n '120,215p' src/main/java/com/clearfolio/viewer/controller/ArtifactController.java

printf '%s\n' '===== Token resolution and parser ====='
sed -n '330,390p' src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java

printf '%s\n' '===== Preauthorization and post-lookup binding ====='
sed -n '180,250p' src/main/java/com/clearfolio/viewer/artifact/ArtifactLinkService.java

printf '%s\n' '===== Invalid-credential regression methods ====='
sed -n '20,95p' src/test/java/com/clearfolio/viewer/controller/ArtifactControllerTokenPreconditionTest.java

printf '%s\n' '===== All production artifact read route declarations ====='
rg -n -C 4 --type java \
  '@(GetMapping|RequestMapping).*artifacts|/artifacts/|Mono<ResponseEntity<byte\[\]>>|ResponseEntity<byte\[\]>' \
  src/main/java

printf '%s\n' '===== All production conversion-job and artifact-store reads ====='
rg -n -C 5 --type java \
  '\.(getJob|getPdf)\s*\(' \
  src/main/java

Length of output: 42203


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '===== ConversionController.downloadArtifact ====='
sed -n '205,305p' src/main/java/com/clearfolio/viewer/controller/ConversionController.java

printf '%s\n' '===== Download route tests and signed-token call sites ====='
rg -n -C 8 --type java \
  '(downloadArtifact|/api/v1/convert/jobs/.*/download|verifyReadToken|resolveToken|preauthorizeReadToken)' \
  src/test/java src/main/java/com/clearfolio/viewer/controller/ConversionController.java

Length of output: 90860


@seonghobae Review completed for exact head 2f16af873714e62870d059324f9fe0bdead29874.

I found one blocking issue.

  • ArtifactController.getPdf meets the requested property. It rejects absent, unsupported, and invalid artifact credentials before job or artifact-store lookup. It also enforces tenant and checksum binding after lookup and before it returns bytes.
  • ConversionController.downloadArtifact does not meet the same property. It accepts artifactToken and Authorization, but it reads the job on Line 231 and the artifact store on Line 242 before it resolves and verifies the artifact token on Lines 248-253. A caller with ARTIFACT_READ can therefore receive job-state or artifact-existence responses for a missing or invalid artifact credential.

Move resolveToken and preauthorizeReadToken(jobId, token) to immediately after tenantAccessService.require(...), before both resource lookups. Retain verifyReadToken(jobId, job, pdfBytes, token) after lookup for mandatory tenant and checksum binding. Add a regression test that verifies no conversion-service or artifact-store interactions when this route receives absent or invalid artifact credentials.

I did not approve or merge the pull request.

⚠️ 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.

Copy link
Copy Markdown
Collaborator Author

Exact-current-head independent review request for 2f16af873714e62870d059324f9fe0bdead29874.

The five-file artifact-read preauthorization slice is mergeable; CI, Security Scan, SAST Semgrep, and fuzz are terminal-success; the only inline finding is resolved and tracked to the separate credential-registry architecture in #319/#344. Invalid or absent credentials are rejected before conversion-job or artifact-store lookup, while post-lookup tenant/checksum binding remains mandatory.

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

Review this exact head read-only. Do not mutate the branch, synthesize author approval, weaken protection, or merge. Protected main has advanced since construction; any base update must regenerate all exact-head evidence.

@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Rate Limit Exceeded

@seonghobae have exceeded the limit for the number of chat messages per hour. Please wait 5 minutes and 27 seconds before sending another message.

Copy link
Copy Markdown
Collaborator Author

Exact-head review/update request for 2f16af873714e62870d059324f9fe0bdead29874.

The artifact preauthorization slice has terminal-success CI, Security Scan, SAST Semgrep, and fuzz, is mergeable, and has zero unresolved threads. Its construction base predates current protected main; update the branch and regenerate base-sensitive evidence before independent approval or merge if required. Preserve the five-file object-existence-oracle repair; credential-source migration remains separately owned by issue #319 and its ordered registry stack.

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

@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown

Rate Limit Exceeded

@seonghobae have exceeded the limit for the number of chat messages per hour. Please wait 5 minutes and 16 seconds before sending another message.

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