Skip to content

fix(security): add privacy-safe administrative audit boundary - #363

Open
seonghobae wants to merge 6 commits into
mainfrom
fix/admin-audit-pseudonym-boundary-main-20260811
Open

fix(security): add privacy-safe administrative audit boundary#363
seonghobae wants to merge 6 commits into
mainfrom
fix/admin-audit-pseudonym-boundary-main-20260811

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Objective

Reconcile the privacy-safe administrative audit primitive from stale descendant #268 directly on current protected main, without carrying its divergent ancestry. This slice establishes domain-separated keyed audit fingerprints for actor, tenant, and job identifiers before later controller wiring.

Test-first state

This Draft starts intentionally RED at exact test-only head 025b8004ff59bc13710e25fc59f328010d34c7ef. The focused test specifies that authenticated and untrusted identifiers never appear raw in administrative audit output; actor/tenant/job correlation must use separate HMAC domains; absent and unconfigured-key states must use controlled markers.

Scope

Only the reusable administrative audit logger primitive, the required AuditPseudonymizer administrative domains/factories, and focused tests. It does not modify AdminController, active PR #341, tenant query PR #342/#361, deletion lifecycle PRs, credential/OIDC work, or canonical documentation.

Acceptance

Observe exact-head RED -> smallest current-base production implementation -> exact-head mvn -B --no-transfer-progress verify with zero missed owned production coverage/public Javadocs -> CI/Security Scan/SAST/fuzz -> review/thread/live-base refetch. Keep Draft until GREEN exact-head evidence exists. Independent write-authorized approval remains a separate merge gate.

Summary by CodeRabbit

  • 새 기능

    • 관리자 작업을 감사 로그로 기록하는 기능을 추가했습니다.
    • 작업 유형, 처리 결과, HTTP 상태, 작업 식별자와 결과 건수를 구조화해 기록합니다.
    • 테넌트와 행위자 식별자는 도메인별 pseudonymization으로 보호됩니다.
    • 원시 식별자, 토큰, 파일명 및 문서 내용은 로그에 포함되지 않습니다.
  • 버그 수정

    • 식별 정보나 결과 건수를 확인할 수 없는 경우 안전한 대체 표기를 제공합니다.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@seonghobae, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 11 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9aa5fc95-d627-4f08-9f5a-78cbd71bc9fe

📥 Commits

Reviewing files that changed from the base of the PR and between 6a3302f and 267e9f0.

📒 Files selected for processing (1)
  • src/test/java/com/clearfolio/viewer/audit/AdministrativeAuditLoggerTest.java
📝 Walkthrough

Walkthrough

관리자 감사 로거와 관리자 식별자용 도메인 분리 pseudonymization 팩토리를 추가했다. 인증 컨텍스트와 요청 헤더를 지원하며, 원시 식별자 대신 fingerprint와 감사 결과를 구조화된 로그로 기록한다. 관련 동작을 Log4j 캡처 테스트로 검증한다.

Changes

관리자 감사 추적

Layer / File(s) Summary
감사 식별자 pseudonymization 계약
src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java
행위자, 테넌트, 작업 식별자에 사용할 도메인 구분 상수와 정적 팩토리 메서드를 추가했다.
관리자 감사 로그 기록
src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java
AdministrativeAuditLoggerAction, Outcome 열거형을 추가했다. 인증 컨텍스트와 요청 헤더에서 식별자를 처리하고, 상태·작업·결과 건수를 구조화된 로그로 기록한다. 누락 값은 absent 또는 unavailable로 기록한다.
감사 로그 검증
src/test/java/com/clearfolio/viewer/audit/AdministrativeAuditLoggerTest.java
컨텍스트와 헤더 기반 fingerprint, 도메인 분리, 누락 값 마커, 감사 필드를 Log4j 캡처 appender로 검증한다.

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

Sequence Diagram(s)

sequenceDiagram
  participant Request as 요청
  participant Logger as AdministrativeAuditLogger
  participant Pseudonymizer as AuditPseudonymizer
  participant Log4j as Log4j

  Request->>Logger: 컨텍스트 또는 헤더와 감사 이벤트 전달
  Logger->>Pseudonymizer: 식별자 pseudonymization 요청
  Pseudonymizer-->>Logger: 도메인별 fingerprint 반환
  Logger->>Log4j: 구조화 감사 로그 기록
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 개인정보 보호형 관리자 감사 경계를 추가하는 주요 변경 사항을 명확하게 요약합니다.
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.
✨ 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/admin-audit-pseudonym-boundary-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 10, 2026 23:20

@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

🧹 Nitpick comments (2)
src/test/java/com/clearfolio/viewer/audit/AdministrativeAuditLoggerTest.java (2)

175-182: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

로거 레벨을 원래 값으로 복원하십시오.

attachAppenderlogger.setLevel(Level.INFO)로 전역 로거 상태를 변경합니다. closeAndDetach는 appender만 제거하고 레벨은 복원하지 않습니다. 변경된 레벨은 같은 JVM의 이후 테스트에 남습니다. 실행 순서에 따라 다른 테스트가 영향을 받을 수 있습니다.

이전 레벨을 저장하고 detach 시 복원하십시오.

♻️ 레벨 복원 적용
     private static CapturingAppender attachAppender() {
         Logger logger = (Logger) LogManager.getLogger(AdministrativeAuditLogger.class);
-        CapturingAppender appender = new CapturingAppender(logger);
+        CapturingAppender appender = new CapturingAppender(logger, logger.getLevel());
         appender.start();
         logger.addAppender(appender);
         logger.setLevel(Level.INFO);
         return appender;
     }
         private final Logger logger;
+        private final Level previousLevel;
         private final List<String> messages = new ArrayList<>();
 
-        private CapturingAppender(Logger logger) {
+        private CapturingAppender(Logger logger, Level previousLevel) {
             super(
                     "administrative-audit-test-appender",
                     null,
                     PatternLayout.newBuilder().withPattern("%m").build(),
                     false,
                     null
             );
             this.logger = logger;
+            this.previousLevel = previousLevel;
         }
         private void closeAndDetach() {
             logger.removeAppender(this);
+            logger.setLevel(previousLevel);
             stop();
         }
🤖 Prompt for 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.

In `@src/test/java/com/clearfolio/viewer/audit/AdministrativeAuditLoggerTest.java`
around lines 175 - 182, Update attachAppender and closeAndDetach to capture the
logger’s existing level before setting Level.INFO, then restore that saved level
when detaching the appender. Ensure cleanup restores the original logger state
for subsequent tests.

105-110: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

동일한 식별자 값으로 도메인 분리를 검증하십시오.

현재 assertion은 tenant, actor, job fingerprint가 서로 다름을 확인합니다. 그러나 세 입력값이 이미 서로 다릅니다. 따라서 이 assertion은 입력값 차이 때문에도 통과합니다. 도메인 분리 자체를 증명하지 못합니다.

세 도메인에 같은 식별자 문자열을 넣고 fingerprint가 다른지 확인하는 assertion을 추가하십시오.

♻️ 도메인 분리 전용 검증 추가 예시
+    `@Test`
+    void separatesDomainsForIdenticalIdentifierValues() {
+        String sharedId = "11111111-1111-1111-1111-111111111111";
+        String actor = AuditPseudonymizer.forAdministrativeActor(AUDIT_SECRET, "v2")
+                .fingerprint(sharedId);
+        String tenant = AuditPseudonymizer.forAdministrativeTenant(AUDIT_SECRET, "v2")
+                .fingerprint(sharedId);
+        String job = AuditPseudonymizer.forAdministrativeJob(AUDIT_SECRET, "v2")
+                .fingerprint(sharedId);
+
+        assertNotEquals(actor, tenant);
+        assertNotEquals(actor, job);
+        assertNotEquals(tenant, job);
+    }
🤖 Prompt for 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.

In `@src/test/java/com/clearfolio/viewer/audit/AdministrativeAuditLoggerTest.java`
around lines 105 - 110, Update the test around AdministrativeAuditLoggerTest to
use the same identifier string for tenant, actor, and job inputs, then assert
their resulting tenantFingerprint, actorFingerprint, and jobFingerprint values
remain distinct. Preserve the existing fingerprint extraction while ensuring the
assertions validate domain separation rather than differing input values.
🤖 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/test/java/com/clearfolio/viewer/audit/AdministrativeAuditLoggerTest.java`:
- Around line 161-166: Update the fieldValue helper in
AdministrativeAuditLoggerTest to explicitly assert that fieldName is present
before calculating the substring bounds. When message.indexOf(prefix) returns
-1, fail with a clear assertion message identifying the missing field instead of
continuing to substring.

---

Nitpick comments:
In
`@src/test/java/com/clearfolio/viewer/audit/AdministrativeAuditLoggerTest.java`:
- Around line 175-182: Update attachAppender and closeAndDetach to capture the
logger’s existing level before setting Level.INFO, then restore that saved level
when detaching the appender. Ensure cleanup restores the original logger state
for subsequent tests.
- Around line 105-110: Update the test around AdministrativeAuditLoggerTest to
use the same identifier string for tenant, actor, and job inputs, then assert
their resulting tenantFingerprint, actorFingerprint, and jobFingerprint values
remain distinct. Preserve the existing fingerprint extraction while ensuring the
assertions validate domain separation rather than differing input values.
🪄 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: 61f85ca8-96c1-4e80-9b36-554227234c0b

📥 Commits

Reviewing files that changed from the base of the PR and between 55d7ae8 and 6a3302f.

📒 Files selected for processing (3)
  • src/main/java/com/clearfolio/viewer/audit/AdministrativeAuditLogger.java
  • src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java
  • src/test/java/com/clearfolio/viewer/audit/AdministrativeAuditLoggerTest.java

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