Skip to content

fix(security): require signed tenant claims on admin endpoints - #268

Closed
seonghobae wants to merge 181 commits into
mainfrom
fix/admin-endpoint-auth-clean
Closed

fix(security): require signed tenant claims on admin endpoints#268
seonghobae wants to merge 181 commits into
mainfrom
fix/admin-endpoint-auth-clean

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Security objective

Make administrative conversion-job endpoints fail closed under signed tenant claims, least-privilege permissions, tenant-scoped persistence/mutation, immutable job identity, privacy-safe audit evidence and restart-safe artifact deletion.

Fresh exact stack state — 2026-08-10

This large child is deliberately not churn-rebased while #270 remains outside protected main. Once the parent integrates, preserve the effective lifecycle/security delta on the new baseline and regenerate every base-sensitive check/review.

Security and lifecycle boundary

  • admin:read for tenant-scoped listing and admin:write for delete/retry; fail closed before repository access for invalid claims/permission;
  • tenant-scoped select/mutate contracts; cross-tenant and missing objects remain indistinguishable;
  • permanently reserved conversion-job UUID identity and lifecycle generation fencing;
  • retry dispatch bound to tenant and immutable generation; stale/replacement work rejected;
  • domain-separated HMAC audit fingerprints without raw actor/tenant/job/signature/filename/path/document/digest/exception-controlled values;
  • signing/audit keys through configuration boundaries with key-strength/separation enforcement;
  • durable deletion intent and generation/digest-bound deletion receipts before destructive cleanup;
  • failed cleanup preserved as restart-safe retry evidence with bounded replay and privacy-safe metrics;
  • standalone filesystem-ledger operation while repository/artifact/outbox boundaries remain replaceable for MSA hosts.

Historical source-head evidence

For unchanged child head 8d3fa3d1e7037c1c91411e8b4b6c014e38d04add, prior CI 31178997607, fuzz 31178997148 and CodeRabbit status were green. Because the current parent is now 46 commits beyond the historical merge base, those remain source-head history only.

Merge gate

Keep Draft. Integrate #270 first. Then reconcile this administrative/deletion delta, verify effective ancestry/diff, rerun exact-head Maven/Surefire/Failsafe, zero-missed owned coverage, public Javadocs, CI, Security Scan, SAST, fuzz, applicable current-head reviews, unresolved-thread, independent-approval and branch-protection evidence. Do not restore demo-tenant fallback, same-UUID replacement, global mutation fallbacks, process-local fairness cursors, exception-selected log content or weakened tests/protection.

seonghobae and others added 27 commits August 5, 2026 12:59
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

테넌트 관리자 보안

Layer / File(s) Summary
서명 인증 및 감사 계약
AGENTS.md, docs/deployment/..., docs/security/..., src/main/java/com/clearfolio/viewer/auth/*, src/main/java/com/clearfolio/viewer/audit/*, src/main/java/com/clearfolio/viewer/security/*, src/test/java/com/clearfolio/viewer/audit/*, src/test/java/com/clearfolio/viewer/auth/*, src/test/java/com/clearfolio/viewer/config/*
관리자 요청은 강한 HMAC 기반 signed tenant claims와 ADMIN_READ 또는 ADMIN_WRITE 권한을 사용합니다. 감사 로그는 actor·tenant·job 식별자를 도메인별 HMAC fingerprint로 기록합니다. tenant claims secret은 config-tree mount에서 로드합니다.
테넌트 범위 저장소 및 원자적 상태 변경
src/main/java/com/clearfolio/viewer/repository/*, src/main/java/com/clearfolio/viewer/service/*, src/test/java/com/clearfolio/viewer/repository/*, src/test/java/com/clearfolio/viewer/service/*
저장소와 서비스가 tenant-scoped 조회·삭제·dead-letter 재시도를 제공합니다. 삭제 후에만 artifact를 정리하고, 승인된 재시도만 worker에 enqueue합니다. primary map과 content-hash index 갱신을 직렬화하고 stale index와 UUID 충돌을 fail-closed 처리합니다.
관리자 엔드포인트 연결 및 검증
src/main/java/com/clearfolio/viewer/controller/AdminController.java, src/test/java/com/clearfolio/viewer/controller/*
목록·삭제·재시도 API가 signed headers와 tenant context를 사용합니다. 누락 대상은 404, 부적격 재시도는 409, 승인된 재시도는 202로 매핑합니다. 인증 실패와 작업 결과를 감사 로그에 기록합니다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant AdminClient
  participant AdminController
  participant TenantAccessService
  participant DefaultDocumentConversionService
  participant InMemoryConversionJobRepository
  participant ConversionJobStateStore
  participant AdministrativeAuditLogger

  AdminClient->>AdminController: signed tenant claims and admin permission
  AdminController->>TenantAccessService: requireSigned
  TenantAccessService-->>AdminController: TenantContext
  AdminController->>DefaultDocumentConversionService: tenant-scoped operation
  DefaultDocumentConversionService->>InMemoryConversionJobRepository: tenant and job identifier
  InMemoryConversionJobRepository-->>DefaultDocumentConversionService: scoped result
  DefaultDocumentConversionService->>ConversionJobStateStore: tenant-bound retry transition
  ConversionJobStateStore-->>DefaultDocumentConversionService: retry outcome
  AdminController->>AdministrativeAuditLogger: action, outcome, HTTP status
  AdminController-->>AdminClient: scoped HTTP response
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning 대부분의 요구사항을 구현했지만, 재시도와 동일 UUID 교체의 동시성 경합을 해결하지 않아 핵심 보안 요구사항을 충족하지 못합니다 [#266]. 서로 다른 작업의 동일 UUID 교체를 거부하거나 불변 tenant/generation 디스패치 계약을 도입하고 결정적 회귀 테스트를 추가하십시오.
Docstring Coverage ⚠️ Warning Docstring coverage is 28.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed 구현, 설정, 문서, OpenAPI 계약 및 테스트 변경은 관리자 인가와 테넌트 범위 보안 목표에 직접 관련됩니다.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 관리자 엔드포인트에 서명된 테넌트 클레임을 요구하는 핵심 보안 변경을 정확하고 간결하게 설명합니다.
✨ 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 fix/admin-endpoint-auth-clean

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 added a commit that referenced this pull request Aug 9, 2026
Acknowledging that this work is superseded by #268.
@seonghobae
seonghobae marked this pull request as draft August 10, 2026 04:40
Base automatically changed from fix/pii-logging-16240128950440010639 to main August 10, 2026 11:42

Copy link
Copy Markdown
Collaborator Author

Supersession decision after fresh post-#270 reconciliation sweep:

  • protected main is 55d7ae8647208e301f282350f076eeddaba61d11;
  • this branch remains exact 8d3fa3d1e7037c1c91411e8b4b6c014e38d04add, Draft, conflict-bearing/non-mergeable, with 181 commits and 139 changed files;
  • all current inline review threads are resolved, but its historical exact-head CI/fuzz do not constitute current-base integration evidence.

The branch is no longer a defensible integration vehicle. Its valuable semantics have been deliberately decomposed onto current-base or bounded successor lanes rather than rebasing the 139-file descendant: tenant-scoped admin deletion #341; storage-scoped tenant list #342; permanent job-id reservation #345; lifecycle serialization #350; deletion state #351; deletion receipt identity #353; fail-closed ledger persistence #357; tenant-scoped lookup #361/#380; privacy-safe administrative audit #363. The remaining end-to-end deletion cleanup/recovery/user journey stays authoritative under #263, and durable generation/attempt/retry/outbox/idempotency/cancellation/redelivery work stays authoritative under #312 and its current bounded successors.

Accordingly, close #268 as superseded. Do not reuse this branch's ancestry, reviews, or checks. Any still-open semantic must advance through its current issue/PR authority and be regenerated against the then-live protected base.

@seonghobae seonghobae closed this Aug 11, 2026
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