Skip to content

fix(security): harden audit pseudonymization and refresh Netty evidence - #270

Open
seonghobae wants to merge 99 commits into
mainfrom
fix/pii-logging-16240128950440010639
Open

fix(security): harden audit pseudonymization and refresh Netty evidence#270
seonghobae wants to merge 99 commits into
mainfrom
fix/pii-logging-16240128950440010639

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Objective

Authoritative buyer-readiness parent for privacy-safe audit evidence, coordinated dependency remediation, deterministic SBOM/attribution evidence, fail-closed exact-head CI, zero-missed production coverage, warning-free public Javadocs, fail-closed test evidence, and tenant-safe document access.

Exact current head: ed3863209109cd24a3cf1f1d6bdcd51db16fbef1.

This PR supersedes closed-unmerged #165, #222, #257, #267, and #269. It remains the authoritative parent of #264, #268, #271, #276, and replacement availability PR #295 (which supersedes closed-unmerged #265 only as a review container). Maintenance PRs #286#290 reconcile the current parent into downstream slices; predecessor-head checks, comments, reviews, approvals, and synthetic-merge results do not transfer.

Security, privacy, and acceptance contract

  • Raw approver identifiers and approval tokens are excluded from policy-override audit logs.
  • Approver evidence uses versioned, domain-separated HMAC pseudonyms; pseudonymized values remain personal data.
  • Policy-signing and audit-pseudonym keys require at least 32 UTF-8 bytes, distinct purposes, and fail-closed configuration during Spring startup and standalone/MSA construction.
  • The Spring-managed Netty family is aligned to 4.1.136.Final.
  • The committed CycloneDX 1.6 SBOM and third-party attribution are deterministically regenerated and checked byte-for-byte.
  • Every pull request base is intended to receive CI; exact pull-request head and synthetic merge compatibility are verified separately once the unfiltered trigger reaches the protected default branch.
  • The stacked-PR workflow regression is executable by both the canonical python3 -m unittest discover -s scripts command and CI's pytest invocation.
  • Maven verify enforces zero missed production lines and branches plus warning-free public Java 21 Javadocs.
  • Surefire evidence is mandatory, must contain at least one executed test, and must contain zero skips, failures, and errors. Optional Failsafe evidence is held to the same rules.
  • Every Maven testsuite explicitly supplies non-negative tests, skipped, failures, and errors counts. XML evidence is bounded, strict UTF-8, DTD/entity-free, and fails closed.
  • Direct conversion-job downloads require authenticated, dedicated artifact:read permission and same-tenant ownership. job:read alone never authorizes document bytes; cross-tenant UUID access is concealed as 404.

Test-first remediation

Strix found a valid cross-tenant IDOR on predecessor head 26563218ae42eaa876c784fcf56b27f8cb810080. RED regressions established missing-claim, missing-permission, cross-tenant, owned-success, and least-privilege artifact:read boundaries before production remediation.

CodeRabbit correctly identified that successful Maven execution alone did not reject disabled, skipped, or zero-executed tests. The implementation added strict bounded Surefire/Failsafe report validation and retained JaCoCo diagnostics.

A later evidence audit found that CI was restricted to pull requests targeting main, leaving stacked PR exact heads without the same acceptance gate. This branch changes CI to pull_request: {} while preserving exact-head checkout, synthetic-merge verification, least-privilege permissions, immutable action pins, and buyer-readiness tests. Until #270 itself is merged, the protected default branch still contains pull_request.branches: [main]; therefore child PRs targeting this stacked base do not yet have usable exact-head Actions evidence and must remain unmerged. No child check is inferred from this branch-local workflow change.

CodeRabbit then correctly found that the initial regression used top-level pytest functions and therefore was not executed by the repository's canonical standard-library discovery command. Exact head ed3863209109cd24a3cf1f1d6bdcd51db16fbef1 converts the regression to a documented unittest.TestCase with standard assertion methods while retaining pytest compatibility.

Exact-head acceptance state

All successful evidence for predecessor heads is stale and non-transferable. For exact current head ed3863209109cd24a3cf1f1d6bdcd51db16fbef1:

  • CI run 31146875930 is complete and successful.
    • Exact-head Maven job 92767994350 checked out and asserted the exact SHA, used Java 21, ran mvn -B --no-transfer-progress verify, executed 476 tests with 0 failures, errors, or skips, analyzed 59 production classes with zero missed production lines and branches, generated warning-free public Javadocs, and recorded surefire: tests=476 skipped=0.
    • Synthetic-merge compatibility job 92767994322 is successful.
    • Buyer-readiness script job 92767994236 is successful.
  • Security Scan run 31146875953 is complete and successful.
  • SAST Semgrep run 31146875908 is complete and successful.
  • Fuzz run 31146875907 is complete and successful.
  • Older same-head attempts 31119467438 (Security Scan) and 31119467763 (CI) remain queued, but are superseded duplicate attempts of workflows that have newer successful same-head runs. They are not used as passing evidence and do not invalidate the newer exact-head successes.
  • Current-head static review reports no actionable source-level blocker; unresolved review threads are zero.
  • CodeRabbit's successful status and current-head advisory comment are not counted independent approval.
  • Formal current-head OpenCode/Noema acceptance and a counted independent repository-write-authorized approval are absent.

Remaining merge gate

Do not merge until formal current-head external review evidence remains free of unresolved actionable findings, a repository-write-authorized independent reviewer submits a counted approval, and every branch-protection and repository-policy rule is satisfied expected-head safely. Do not weaken tests, bypass protection, infer approval from successful checks or bot comments, or publish a release before integrated release acceptance succeeds.

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

coderabbitai Bot commented Aug 5, 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: 7 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

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: 2a6a1f39-23a3-45fb-92da-39a2a615a8b6

📥 Commits

Reviewing files that changed from the base of the PR and between 91091dd and ed38632.

📒 Files selected for processing (11)
  • .github/workflows/ci.yml
  • CHANGELOG.md
  • docs/engineering/acceptance-criteria.md
  • docs/security/2026-07-02-auth-tenant-model.md
  • scripts/test_ci_workflow_stack_coverage.py
  • scripts/test_verify_maven_test_reports.py
  • scripts/verify_maven_test_reports.py
  • src/main/java/com/clearfolio/viewer/auth/TenantPermissions.java
  • src/main/java/com/clearfolio/viewer/controller/ConversionController.java
  • src/test/java/com/clearfolio/viewer/controller/ConversionControllerTest.java
  • src/test/java/com/clearfolio/viewer/controller/ConversionDownloadAuthorizationTest.java
📝 Walkthrough

Walkthrough

이번 변경은 정확한 커밋 검증, Maven 품질 게이트, Netty SBOM 일치성, 감사 식별자 가명화, 입력값 보호, 저장소 경계 테스트를 추가하고 관련 문서와 설정을 갱신합니다.

Changes

검증 게이트와 의존성 증거

Layer / File(s) Summary
CI·Maven·SBOM 검증 게이트
.github/workflows/*, pom.xml, AGENTS.md, src/test/java/com/clearfolio/viewer/config/DependencyPolicyTest.java, scripts/*
PR head와 병합 커밋을 검증하고 mvn verify, JaCoCo, Javadoc, Netty 및 SBOM 계약 검사를 실행합니다.
의존성 증거와 릴리스 기록
docs/legal/*, docs/security/*, docs/qa/evidence/*, CHANGELOG.md
Netty, PDFBox, Commons Logging, pdfjs-dist 버전과 SBOM, attribution, acceptance evidence를 갱신합니다.

감사 가명화와 경계 보호

Layer / File(s) Summary
감사 가명화와 키 분리
src/main/java/com/clearfolio/viewer/security/*, src/main/java/com/clearfolio/viewer/service/*, src/main/resources/application.yml, docs/security/*, src/test/java/com/clearfolio/viewer/security/*, src/test/java/com/clearfolio/viewer/service/*
정책 키와 감사 키를 검증하고, AuditPseudonymizerapproverFingerprint를 생성하며, 감사 로그에서 원시 식별자를 제외합니다.
API·파일·서비스 경계 보호
src/main/java/com/clearfolio/viewer/api/*, src/main/java/com/clearfolio/viewer/artifact/*, src/main/java/com/clearfolio/viewer/controller/*, src/main/java/com/clearfolio/viewer/repository/*, src/test/java/com/clearfolio/viewer/*
오류 응답 입력을 마스킹하고 파일명·파일 읽기·삭제·테넌트 범위 동작을 보강합니다. 공개 API Javadoc과 기본 생성자도 추가합니다.

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

Sequence Diagram(s)

sequenceDiagram
  participant PullRequest
  participant CIWorkflow
  participant MavenVerify
  participant JaCoCo
  participant Javadoc
  PullRequest->>CIWorkflow: PR head SHA 전달
  CIWorkflow->>CIWorkflow: checkout SHA 검증
  CIWorkflow->>MavenVerify: verify 실행
  MavenVerify->>JaCoCo: coverage gate 실행
  MavenVerify->>Javadoc: public API 문서 gate 실행
  JaCoCo-->>CIWorkflow: coverage 결과 반환
  Javadoc-->>CIWorkflow: 문서 검증 결과 반환
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.17% 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 제목은 감사 pseudonymization 강화와 Netty 증거 갱신이라는 PR의 주요 변경 사항을 정확하고 간결하게 요약합니다.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/pii-logging-16240128950440010639

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo='ContextualWisdomLab/clearfolio'
pr='270'
head='c1239e20b048a582b19cb9eeb90f2c29f7c8f814'

printf '%s\n' '== Exact commit and PR state =='
git cat-file -t "$head"
git show -s --format='commit=%H%nparents=%P%nsubject=%s' "$head"
git diff --name-status "${head}^" "$head"
gh pr view "$pr" --repo "$repo" \
  --json headRefOid,baseRefOid,mergeStateStatus,reviewDecision,reviews,statusCheckRollup \
  --jq '{headRefOid,baseRefOid,mergeStateStatus,reviewDecision,reviews:[.reviews[]|{author:.author.login,state,commit:.commit.oid}],checks:[.statusCheckRollup[]|{name,status,conclusion,app:.app.slug}]}'
gh api "repos/$repo/commits/$head/check-runs?per_page=100" \
  --jq '[.check_runs[] | {name,status,conclusion,app:.app.slug,details_url}]'
gh api graphql -F owner='ContextualWisdomLab' -F name='clearfolio' -F number="$pr" -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) { nodes { isResolved } }
    }
  }
}' --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length'

printf '%s\n' '== Changed CI scope and workflow test =='
ast-grep outline scripts/test_ci_workflow_stack_coverage.py --items all --view expanded
git diff --unified=100 "${head}^" "$head" -- \
  .github/workflows/ci.yml scripts/test_ci_workflow_stack_coverage.py
sed -n '1,320p' scripts/test_ci_workflow_stack_coverage.py
rg -n -C 12 \
  '(pull_request:|merge_group:|pull_request\.head\.sha|github\.sha|verify_maven_test_reports|mvn -B --no-transfer-progress verify|actions/checkout|persist-credentials|permissions:|contents:\s*write|pull-requests:\s*write|git push|gh (pr|api|issue))' \
  .github/workflows/ci.yml .github/workflows/fuzz.yml

printf '%s\n' '== Download authorization and audit-key implementation =='
for path in \
  src/main/java/com/clearfolio/viewer/auth/TenantPermissions.java \
  src/main/java/com/clearfolio/viewer/controller/ConversionController.java \
  src/test/java/com/clearfolio/viewer/controller/ConversionDownloadAuthorizationTest.java \
  src/main/java/com/clearfolio/viewer/security/AuditKeySeparationGuard.java \
  src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java \
  src/main/java/com/clearfolio/viewer/service/DefaultDocumentValidationService.java \
  src/main/resources/application.yml
do
  printf '\n===== %s =====\n' "$path"
  ast-grep outline "$path" --items all --view expanded || true
  rg -n -C 24 \
    '(downloadArtifact|ARTIFACT_READ|JOB_READ|artifactStore\.getPdf|conversionService\.getJob|requireSameTenant|HmacSHA256|AuditKeySeparationGuard\.validate|approverFingerprint|tokenFingerprint|configtree)' \
    "$path" || true
done

printf '%s\n' '== Maven evidence gate and build enforcement =='
sed -n '1,320p' scripts/verify_maven_test_reports.py
rg -n -C 9 \
  '(netty.version|4\.1\.136\.Final|jacoco-maven-plugin|MISSEDCOUNT|maven-javadoc-plugin|doclint|failOnWarnings|failOnError)' \
  pom.xml

printf '%s\n' '== SBOM and attribution invariants =='
python3 - <<'PY'
import json
from pathlib import Path
p = Path("docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json")
bom = json.loads(p.read_text(encoding="utf-8"))
components = bom["components"]
refs = {c["bom-ref"] for c in components}
netty = [c for c in components if c.get("group") == "io.netty"]
netty_refs = {c["bom-ref"] for c in netty}
entries = bom["dependencies"]
sources = {e["ref"] for e in entries}
targets = {target for e in entries for target in e.get("dependsOn", [])}
metadata_ref = bom["metadata"]["component"].get("bom-ref")
print("component_count=", len(components))
print("netty_component_count=", len(netty))
print("netty_versions=", sorted({c["version"] for c in netty}))
print("netty_purl_ref_version_coherent=", all(
    c["purl"] == c["bom-ref"] and "`@4.1.136.Final`" in c["purl"] for c in netty))
print("netty_dependency_edges_complete=", netty_refs <= sources and netty_refs <= targets)
print("only_metadata_non_component_refs=", (sources - refs | targets - refs) <= {metadata_ref})
print("legacy_netty_present=", "4.1.135.Final" in p.read_text(encoding="utf-8"))
PY
rg -n -C 8 \
  '(byte-for-byte|render_third_party_attribution|read_bytes|sha256)' \
  scripts/test_render_third_party_attribution.py

Length of output: 76716


@seonghobae I reviewed exact head c1239e20b048a582b19cb9eeb90f2c29f7c8f814.

I found no actionable source-level blocker in the inspected scope.

  • ConversionController.downloadArtifact(...) requires artifact:read before it calls conversionService.getJob(...).

  • A caller with only job:read receives 403 before service or artifact access.

  • The controller checks tenant ownership before ArtifactStore.getPdf(...).

  • A cross-tenant request returns 404 and does not access the artifact.

  • The focused tests cover missing claims, missing artifact:read, cross-tenant access, and owned access.

  • AuditPseudonymizer uses versioned, domain-separated HmacSHA256.

  • AuditKeySeparationGuard.validate(...) runs during direct DefaultDocumentValidationService construction.

  • The accepted override log records approverFingerprint and tokenFingerprint.

  • The accepted override log does not record the raw approver identifier or approval token.

  • The config tree supplies the policy secret, audit pseudonym secret, and audit key version.

  • The SBOM contains 61 components and 17 io.netty components.

  • All listed Netty components use 4.1.136.Final.

  • Netty PURLs, BOM references, and dependency edges are coherent.

  • The attribution tests retain byte-for-byte renderer output verification.

  • The Maven report gate uses a bounded 16 MiB read.

  • The gate accepts UTF-8 with an optional BOM.

  • The gate rejects NUL bytes, DTD declarations, entity declarations, malformed XML, missing counts, negative counts, zero tests, skips, failures, and errors.

  • JaCoCo rejects all missed production lines and branches.

  • Maven Javadoc runs at verify with doclint=all, failOnError=true, and failOnWarnings=true.

  • .github/workflows/ci.yml now uses pull_request: {}.

  • scripts/test_ci_workflow_stack_coverage.py rejects the previous main-only trigger.

  • Exact-head jobs check out and verify github.event.pull_request.head.sha.

  • The separate merge-compatibility job verifies github.sha.

  • The Maven and buyer-readiness paths retain read-only permissions and disabled persisted checkout credentials.

  • I found no write-scoped workflow permission or repository mutation command.

I do not submit APPROVE.

GitHub reports strix as in_progress for this exact head. GitHub also reports mergeStateStatus=BLOCKED and reviewDecision=REVIEW_REQUIRED. There are zero unresolved review threads, but no counted approval exists for this head. The active check and the required independent repository-authorized approval must complete before merge.

⚠️ Action not completed

Review rate limited.

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.

seonghobae added a commit that referenced this pull request Aug 6, 2026
Record authoritative parent #270 exact head as an ancestor of child #268 after explicitly restoring the parent-only broad pull-request CI trigger and regression test. This is stack maintenance only; all child checks and reviews must rerun on the resulting exact head.

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@opencode-agent @cwl-noema-review Please independently review exact current head ed3863209109cd24a3cf1f1d6bdcd51db16fbef1 only, against protected main head f3cc09a9838f0f88c81a2ceae22138fab80a2edb and synthetic merge revision 0f1817b60f0fb0e0e6d595c4724d2a586c1ec722. The new delta converts the stacked-PR CI regression from top-level pytest functions to a documented unittest.TestCase so the canonical python3 -m unittest discover -s scripts command executes it, while preserving CI pytest compatibility. Re-evaluate the full current-head privacy, tenant authorization, dependency, SBOM/provenance, exact-head, synthetic-merge, complete-test-evidence, 100% coverage, and Javadoc contract. Do not transfer predecessor approvals or successful checks. Submit current actionable findings or a formal review only. A separate counted repository-write-authorized independent approval remains mandatory.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo='ContextualWisdomLab/clearfolio'
pr='270'
head='ed3863209109cd24a3cf1f1d6bdcd51db16fbef1'
base='f3cc09a9838f0f88c81a2ceae22138fab80a2edb'
merge='0f1817b60f0fb0e0e6d595c4724d2a586c1ec722'

printf '%s\n' '== Commit identity, ancestry, and requested delta =='
git cat-file -t "$head"
git show -s --format='head=%H%nparents=%P%nsubject=%s' "$head"
git cat-file -t "$base"
git merge-base --is-ancestor "$base" "$head" && echo 'base_is_ancestor=true'
git cat-file -t "$merge" || true
git diff --name-status "${head}^" "$head"
git diff --unified=100 "${head}^" "$head" -- \
  scripts/test_ci_workflow_stack_coverage.py \
  .github/workflows/ci.yml \
  CHANGELOG.md \
  docs/engineering/acceptance-criteria.md

printf '%s\n' '== CI stack test implementation and discovery references =='
ast-grep outline scripts/test_ci_workflow_stack_coverage.py --items all --view expanded
sed -n '1,360p' scripts/test_ci_workflow_stack_coverage.py | nl -ba
rg -n -C 8 --glob '*.py' --glob 'pyproject.toml' --glob 'pytest.ini' --glob 'setup.cfg' \
  '(test_ci_workflow_stack_coverage|unittest|pytest|discover)' \
  scripts README.md AGENTS.md 2>/dev/null || true

printf '%s\n' '== Exact-head and synthetic-merge workflow controls =='
rg -n -C 12 \
  '(pull_request:|merge_group:|pull_request\.head\.sha|github\.sha|actions/checkout|persist-credentials|permissions:|mvn -B --no-transfer-progress verify|verify_maven_test_reports|python3 -m unittest discover|python -m pytest)' \
  .github/workflows/ci.yml .github/workflows/fuzz.yml

printf '%s\n' '== Tenant authorization and audit pseudonymization =='
rg -n -C 18 --glob '*.java' \
  '(downloadArtifact|ARTIFACT_READ|JOB_READ|conversionService\.getJob|requireSameTenant|artifactStore\.getPdf|AuditKeySeparationGuard\.validate|HmacSHA256|approverFingerprint|tokenFingerprint)' \
  src/main/java src/test/java

printf '%s\n' '== Maven gates, Netty, report parser, and write-scope scan =='
rg -n -C 8 \
  '(netty.version|4\.1\.136\.Final|jacoco-maven-plugin|MISSEDCOUNT|maven-javadoc-plugin|doclint|failOnWarnings|failOnError)' \
  pom.xml
rg -n -C 7 \
  '(MAX|16 \* 1024|UTF-8|DOCTYPE|ENTITY|NUL|tests|skipped|failures|errors)' \
  scripts/verify_maven_test_reports.py
rg -n -C 4 \
  '(contents:\s*write|pull-requests:\s*write|issues:\s*write|id-token:\s*write|git push|gh (pr|api|issue)|curl .*(-X|--request) *(POST|PUT|PATCH|DELETE))' \
  .github/workflows || true

printf '%s\n' '== SBOM and attribution invariants =='
python3 - <<'PY'
import json
from pathlib import Path
sbom_path = Path("docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json")
sbom = json.loads(sbom_path.read_text(encoding="utf-8"))
components = sbom["components"]
refs = {c["bom-ref"] for c in components}
netty = [c for c in components if c.get("group") == "io.netty"]
netty_refs = {c["bom-ref"] for c in netty}
sources = {d["ref"] for d in sbom["dependencies"]}
targets = {x for d in sbom["dependencies"] for x in d.get("dependsOn", [])}
metadata_ref = sbom["metadata"]["component"].get("bom-ref")
print("component_count=", len(components))
print("netty_count=", len(netty))
print("netty_versions=", sorted({c["version"] for c in netty}))
print("netty_purls_refs_coherent=", all(c["purl"] == c["bom-ref"] and "`@4.1.136.Final`" in c["purl"] for c in netty))
print("netty_edges_complete=", netty_refs <= sources and netty_refs <= targets)
print("only_metadata_non_component_refs=", (sources - refs | targets - refs) <= {metadata_ref})
print("legacy_netty_present=", "4.1.135.Final" in sbom_path.read_text(encoding="utf-8"))
PY
rg -n -C 8 \
  '(byte-for-byte|render_third_party_attribution|read_bytes|write_bytes|assertEqual)' \
  scripts/test_render_third_party_attribution.py

printf '%s\n' '== Exact-head GitHub state =='
gh pr view "$pr" --repo "$repo" \
  --json headRefOid,baseRefOid,mergeStateStatus,reviewDecision,reviews,statusCheckRollup \
  --jq '{headRefOid,baseRefOid,mergeStateStatus,reviewDecision,reviews:[.reviews[]|{author:.author.login,state,commit:.commit.oid}],checks:[.statusCheckRollup[]|{name,status,conclusion,app:.app.slug}]}'
gh api "repos/$repo/commits/$head/check-runs?per_page=100" \
  --jq '[.check_runs[]|{name,status,conclusion,app:.app.slug,details_url}]'
gh api graphql -F owner='ContextualWisdomLab' -F name='clearfolio' -F number="$pr" -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) { nodes { isResolved } }
    }
  }
}' --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length'

Length of output: 8289


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo='ContextualWisdomLab/clearfolio'
pr='270'
head='ed3863209109cd24a3cf1f1d6bdcd51db16fbef1'

printf '%s\n' '== CI stack test and discovery =='
sed -n '1,220p' scripts/test_ci_workflow_stack_coverage.py
rg -n -C 6 --glob '*.py' --glob 'pyproject.toml' --glob 'pytest.ini' --glob 'setup.cfg' \
  '(test_ci_workflow_stack_coverage|unittest|pytest|discover)' \
  scripts README.md AGENTS.md 2>/dev/null || true

printf '%s\n' '== Exact-head and synthetic-merge workflow controls =='
rg -n -C 12 \
  '(pull_request:|merge_group:|pull_request\.head\.sha|github\.sha|actions/checkout|persist-credentials|permissions:|mvn -B --no-transfer-progress verify|verify_maven_test_reports|python3 -m unittest discover|python -m pytest)' \
  .github/workflows/ci.yml .github/workflows/fuzz.yml

printf '%s\n' '== Tenant authorization and audit pseudonymization =='
rg -n -C 18 --glob '*.java' \
  '(downloadArtifact|ARTIFACT_READ|JOB_READ|conversionService\.getJob|requireSameTenant|artifactStore\.getPdf|AuditKeySeparationGuard\.validate|HmacSHA256|approverFingerprint|tokenFingerprint)' \
  src/main/java src/test/java

printf '%s\n' '== Maven gates, report parser, and workflow write-scope scan =='
rg -n -C 8 \
  '(netty.version|4\.1\.136\.Final|jacoco-maven-plugin|MISSEDCOUNT|maven-javadoc-plugin|doclint|failOnWarnings|failOnError)' \
  pom.xml
sed -n '1,280p' scripts/verify_maven_test_reports.py
rg -n -C 4 \
  '(contents:\s*write|pull-requests:\s*write|issues:\s*write|id-token:\s*write|git push|gh (pr|api|issue)|curl .*(-X|--request) *(POST|PUT|PATCH|DELETE))' \
  .github/workflows || true

printf '%s\n' '== SBOM and attribution invariants =='
python3 - <<'PY'
import json
from pathlib import Path
sbom_path = Path("docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json")
sbom = json.loads(sbom_path.read_text(encoding="utf-8"))
components = sbom["components"]
refs = {c["bom-ref"] for c in components}
netty = [c for c in components if c.get("group") == "io.netty"]
netty_refs = {c["bom-ref"] for c in netty}
sources = {d["ref"] for d in sbom["dependencies"]}
targets = {x for d in sbom["dependencies"] for x in d.get("dependsOn", [])}
metadata_ref = sbom["metadata"]["component"].get("bom-ref")
print("component_count=", len(components))
print("netty_count=", len(netty))
print("netty_versions=", sorted({c["version"] for c in netty}))
print("netty_purls_refs_coherent=", all(c["purl"] == c["bom-ref"] and "`@4.1.136.Final`" in c["purl"] for c in netty))
print("netty_edges_complete=", netty_refs <= sources and netty_refs <= targets)
print("only_metadata_non_component_refs=", (sources - refs | targets - refs) <= {metadata_ref})
print("legacy_netty_present=", "4.1.135.Final" in sbom_path.read_text(encoding="utf-8"))
PY
rg -n -C 8 \
  '(byte-for-byte|render_third_party_attribution|read_bytes|write_bytes|assertEqual)' \
  scripts/test_render_third_party_attribution.py

printf '%s\n' '== Exact-head GitHub state =='
gh pr view "$pr" --repo "$repo" \
  --json headRefOid,baseRefOid,mergeStateStatus,reviewDecision,reviews,statusCheckRollup \
  --jq '{headRefOid,baseRefOid,mergeStateStatus,reviewDecision,reviews:[.reviews[]|{author:.author.login,state,commit:.commit.oid}],checks:[.statusCheckRollup[]|{name,status,conclusion,app:.app.slug}]}'
gh api "repos/$repo/commits/$head/check-runs?per_page=100" \
  --jq '[.check_runs[]|{name,status,conclusion,app:.app.slug,details_url}]'
gh api graphql -F owner='ContextualWisdomLab' -F name='clearfolio' -F number="$pr" -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) { nodes { isResolved } }
    }
  }
}' --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length'

Length of output: 204362


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== CI coverage test and workflow contract =='
sed -n '1,100p' scripts/test_ci_workflow_stack_coverage.py
rg -n -C 8 \
  '(pull_request:|merge_group:|name: Maven test|name: Maven merge compatibility|name: Buyer-readiness script tests|github\.event\.pull_request\.head\.sha|ref:|EXPECTED_SHA|persist-credentials|permissions:|verify_maven_test_reports)' \
  .github/workflows/ci.yml

printf '%s\n' '== Direct-download authorization order =='
rg -n -C 25 \
  '(downloadArtifact\s*\(|TenantPermissions\.ARTIFACT_READ|conversionService\.getJob|requireSameTenant|artifactStore\.getPdf)' \
  src/main/java/com/clearfolio/viewer/controller/ConversionController.java
rg -n -C 12 \
  '(downloadRejectsMissingTenantClaims|downloadRejectsJobReadWithoutArtifactRead|downloadConcealsCrossTenantJob|downloadReturnsOwnedSucceededArtifact|verifyNoInteractions|never\(\)\.getPdf)' \
  src/test/java/com/clearfolio/viewer/controller/ConversionDownloadAuthorizationTest.java

printf '%s\n' '== Audit key and pseudonym contract =='
rg -n -C 14 \
  '(MINIMUM|requireStrong|requireAudit|requireDistinct|validate\(|MessageDigest\.isEqual)' \
  src/main/java/com/clearfolio/viewer/security/AuditKeySeparationGuard.java
rg -n -C 12 \
  '(HmacSHA256|DOMAIN|fingerprint|keyVersion|Mac\.getInstance)' \
  src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java
rg -n -C 12 \
  '(AuditKeySeparationGuard\.validate|approverFingerprint|tokenFingerprint|LOGGER|logger\.)' \
  src/main/java/com/clearfolio/viewer/service/DefaultDocumentValidationService.java

printf '%s\n' '== Config-tree and attribution assertions =='
sed -n '1,100p' src/main/resources/application.yml
rg -n -C 6 \
  '(render_markdown\(sbom\)|actual_attribution|Netty dependency edge|4\.1\.135\.Final)' \
  scripts/test_render_third_party_attribution.py

Length of output: 38851


@seonghobae I reviewed exact head ed3863209109cd24a3cf1f1d6bdcd51db16fbef1 against base f3cc09a9838f0f88c81a2ceae22138fab80a2edb.

I found no actionable source-level blocker.

  • The delta changes only scripts/test_ci_workflow_stack_coverage.py.
  • CiWorkflowStackCoverageTest is a unittest.TestCase.
  • The test preserves both assertions for all-base PR coverage and exact-head/synthetic-merge CI evidence.
  • The __main__ entry point runs unittest.main().
  • The test remains compatible with pytest discovery.

The CI controls remain present.

  • .github/workflows/ci.yml uses pull_request: {}.
  • Exact-head jobs check out github.event.pull_request.head.sha || github.sha.
  • Exact-head jobs verify EXPECTED_SHA.
  • The Maven merge compatibility job verifies github.sha.
  • Maven jobs run mvn -B --no-transfer-progress verify and scripts/verify_maven_test_reports.py.
  • Workflow permissions remain contents: read.
  • Checkout uses persist-credentials: false.

The authorization and privacy controls remain consistent.

  • downloadArtifact(...) requires TenantPermissions.ARTIFACT_READ before job lookup.
  • The controller checks tenant ownership before artifactStore.getPdf(...).
  • Tests verify missing-claims rejection, job:read rejection, cross-tenant 404 concealment, and owned artifact access.
  • AuditKeySeparationGuard requires a 32-byte policy key, a dedicated audit key, and distinct key values.
  • Direct DefaultDocumentValidationService construction invokes the same validation.
  • AuditPseudonymizer uses a versioned, domain-separated HmacSHA256 fingerprint.
  • Accepted override logs contain fingerprints, not raw approver IDs or approval tokens.
  • application.yml loads the secrets through an optional Spring config tree.

The evidence gates remain consistent.

  • JaCoCo rejects missed production lines and branches.
  • Maven Javadoc uses doclint=all, failOnError=true, and failOnWarnings=true.
  • The Maven report gate uses a bounded 16 MiB read and rejects invalid, incomplete, skipped, failed, or errored test evidence.
  • The SBOM has 61 components and 17 Netty components at 4.1.136.Final.
  • Netty PURLs, BOM references, and dependency edges are coherent.
  • Attribution tests require the rendered output to equal the committed attribution text.

I do not submit APPROVE.

At inspection time, the exact-head Maven, merge-compatibility, buyer-readiness, security, Semgrep, fuzz, and other checks were queued or in progress. GitHub reported mergeStateStatus=BLOCKED and reviewDecision=REVIEW_REQUIRED. These incomplete checks do not count as passing evidence. A completed exact-head protection set and a counted repository-authorized independent approval remain required before merge.

You are interacting with an AI system.

@seonghobae
seonghobae marked this pull request as draft August 7, 2026 04:12
auto-merge was automatically disabled August 7, 2026 04:12

Pull request was converted to draft

@seonghobae
seonghobae marked this pull request as ready for review August 7, 2026 04:12
@seonghobae seonghobae closed this Aug 7, 2026
@seonghobae seonghobae reopened this Aug 7, 2026
@seonghobae
seonghobae marked this pull request as draft August 7, 2026 04:21
@seonghobae
seonghobae marked this pull request as ready for review August 7, 2026 04:21
@seonghobae
seonghobae marked this pull request as draft August 7, 2026 04:24
@seonghobae
seonghobae marked this pull request as ready for review August 7, 2026 04:25
@seonghobae
seonghobae enabled auto-merge (squash) August 7, 2026 04:27

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@opencode-agent @cwl-noema-review Please independently review exact current head ed3863209109cd24a3cf1f1d6bdcd51db16fbef1 only. Fresh exact-head evidence is complete and successful: CI 31146875930 (Maven exact-head 92767994350, synthetic merge 92767994322, buyer-readiness 92767994236), Security Scan 31146875953, SAST Semgrep 31146875908, and fuzz 31146875907. Confirm whether any actionable current-head finding remains. Do not transfer predecessor reviews, approvals, or failed/queued attempts. A separate counted approval from an independent repository-write-authorized reviewer remains mandatory.

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

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.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo='ContextualWisdomLab/clearfolio'
pr='270'
head='ed3863209109cd24a3cf1f1d6bdcd51db16fbef1'
base='f3cc09a9838f0f88c81a2ceae22138fab80a2edb'

printf '%s\n' '== Exact commit and PR state =='
git cat-file -t "$head"
git show -s --format='head=%H%nparents=%P%nsubject=%s' "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'base_is_ancestor=true'
git diff --name-status "${head}^" "$head"
gh pr view "$pr" --repo "$repo" \
  --json headRefOid,baseRefOid,mergeStateStatus,reviewDecision,reviews,statusCheckRollup \
  --jq '{headRefOid,baseRefOid,mergeStateStatus,reviewDecision,reviews:[.reviews[]|{author:.author.login,state,commit:.commit.oid}],checks:[.statusCheckRollup[]|{name,status,conclusion,app:.app.slug}]}'
gh api "repos/$repo/commits/$head/check-runs?per_page=100" \
  --jq '[.check_runs[]|{name,status,conclusion,app:.app.slug,details_url}]'
gh api graphql -F owner='ContextualWisdomLab' -F name='clearfolio' -F number="$pr" -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) { nodes { isResolved } }
    }
  }
}' --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length'

printf '%s\n' '== Delta and CI test discovery =='
git diff --unified=100 "${head}^" "$head" -- \
  scripts/test_ci_workflow_stack_coverage.py \
  .github/workflows/ci.yml
ast-grep outline scripts/test_ci_workflow_stack_coverage.py --items all --view expanded
sed -n '1,260p' scripts/test_ci_workflow_stack_coverage.py | nl -ba
rg -n -C 10 \
  '(pull_request:|merge_group:|pull_request\.head\.sha|github\.sha|actions/checkout|persist-credentials|permissions:|mvn -B --no-transfer-progress verify|verify_maven_test_reports|unittest discover|pytest)' \
  .github/workflows/ci.yml .github/workflows/fuzz.yml

printf '%s\n' '== Authorization, audit, Maven, and workflow controls =='
rg -n -C 16 --glob '*.java' \
  '(downloadArtifact|ARTIFACT_READ|conversionService\.getJob|requireSameTenant|artifactStore\.getPdf|AuditKeySeparationGuard\.validate|HmacSHA256|approverFingerprint|tokenFingerprint)' \
  src/main/java src/test/java
rg -n -C 8 \
  '(netty.version|4\.1\.136\.Final|jacoco-maven-plugin|MISSEDCOUNT|maven-javadoc-plugin|doclint|failOnWarnings|failOnError)' \
  pom.xml
sed -n '1,280p' scripts/verify_maven_test_reports.py
rg -n -C 4 \
  '(contents:\s*write|pull-requests:\s*write|issues:\s*write|id-token:\s*write|git push|gh (pr|api|issue)|curl .*(-X|--request) *(POST|PUT|PATCH|DELETE))' \
  .github/workflows || true

printf '%s\n' '== SBOM and attribution invariants =='
python3 - <<'PY'
import json
from pathlib import Path

p = Path("docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json")
bom = json.loads(p.read_text(encoding="utf-8"))
components = bom["components"]
refs = {c["bom-ref"] for c in components}
netty = [c for c in components if c.get("group") == "io.netty"]
netty_refs = {c["bom-ref"] for c in netty}
sources = {d["ref"] for d in bom["dependencies"]}
targets = {target for d in bom["dependencies"] for target in d.get("dependsOn", [])}
metadata_ref = bom["metadata"]["component"].get("bom-ref")
print("component_count=", len(components))
print("netty_component_count=", len(netty))
print("netty_versions=", sorted({c["version"] for c in netty}))
print("netty_purl_ref_version_coherent=", all(
    c["purl"] == c["bom-ref"] and "`@4.1.136.Final`" in c["purl"] for c in netty))
print("netty_edges_complete=", netty_refs <= sources and netty_refs <= targets)
print("only_metadata_non_component_refs=", (sources - refs | targets - refs) <= {metadata_ref})
print("legacy_netty_present=", "4.1.135.Final" in p.read_text(encoding="utf-8"))
PY
rg -n -C 8 \
  '(render_markdown\(sbom\)|read_bytes|byte-for-byte|assertEqual|actual_attribution)' \
  scripts/test_render_third_party_attribution.py

Length of output: 27527


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo='ContextualWisdomLab/clearfolio'
pr='270'
head='ed3863209109cd24a3cf1f1d6bdcd51db16fbef1'

printf '%s\n' '== Current exact-head non-success checks =='
gh api "repos/$repo/commits/$head/check-runs?per_page=100" \
  --jq '[.check_runs[] | select(.status != "completed" or (.conclusion != "success" and .conclusion != "neutral" and .conclusion != "skipped")) | {name,status,conclusion,app:.app.slug,details_url,started_at,completed_at}]'

printf '%s\n' '== Current exact-head workflow runs =='
gh api "repos/$repo/actions/runs?head_sha=$head&per_page=100" \
  --jq '[.workflow_runs[] | {id,name,event,status,conclusion,head_sha,run_attempt,created_at,updated_at,html_url}] | sort_by(.created_at)'

printf '%s\n' '== CI discovery test and workflow semantics =='
sed -n '1,220p' scripts/test_ci_workflow_stack_coverage.py
rg -n -C 12 \
  '(pull_request:|merge_group:|pull_request\.head\.sha|github\.sha|actions/checkout|persist-credentials|permissions:|mvn -B --no-transfer-progress verify|verify_maven_test_reports|unittest discover|pytest)' \
  .github/workflows/ci.yml .github/workflows/fuzz.yml

printf '%s\n' '== Tenant authorization and audit controls =='
rg -n -C 16 --glob '*.java' \
  '(downloadArtifact|ARTIFACT_READ|conversionService\.getJob|requireSameTenant|artifactStore\.getPdf|AuditKeySeparationGuard\.validate|HmacSHA256|approverFingerprint|tokenFingerprint)' \
  src/main/java src/test/java
sed -n '1,260p' src/main/java/com/clearfolio/viewer/security/AuditKeySeparationGuard.java
sed -n '1,280p' src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java
sed -n '1,340p' src/main/java/com/clearfolio/viewer/service/DefaultDocumentValidationService.java

printf '%s\n' '== Maven and workflow enforcement =='
sed -n '1,300p' scripts/verify_maven_test_reports.py
rg -n -C 8 \
  '(netty.version|4\.1\.136\.Final|jacoco-maven-plugin|MISSEDCOUNT|maven-javadoc-plugin|doclint|failOnWarnings|failOnError)' \
  pom.xml
rg -n -C 4 \
  '(contents:\s*write|pull-requests:\s*write|issues:\s*write|id-token:\s*write|git push|gh (pr|api|issue)|curl .*(-X|--request) *(POST|PUT|PATCH|DELETE))' \
  .github/workflows || true

printf '%s\n' '== SBOM and attribution invariants =='
python3 - <<'PY'
import json
from pathlib import Path

p = Path("docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json")
bom = json.loads(p.read_text(encoding="utf-8"))
components = bom["components"]
refs = {c["bom-ref"] for c in components}
netty = [c for c in components if c.get("group") == "io.netty"]
netty_refs = {c["bom-ref"] for c in netty}
sources = {d["ref"] for d in bom["dependencies"]}
targets = {target for d in bom["dependencies"] for target in d.get("dependsOn", [])}
metadata_ref = bom["metadata"]["component"].get("bom-ref")
print("component_count=", len(components))
print("netty_component_count=", len(netty))
print("netty_versions=", sorted({c["version"] for c in netty}))
print("netty_purl_ref_version_coherent=", all(
    c["purl"] == c["bom-ref"] and "`@4.1.136.Final`" in c["purl"] for c in netty))
print("netty_edges_complete=", netty_refs <= sources and netty_refs <= targets)
print("only_metadata_non_component_refs=", (sources - refs | targets - refs) <= {metadata_ref})
print("legacy_netty_present=", "4.1.135.Final" in p.read_text(encoding="utf-8"))
PY
rg -n -C 8 \
  '(render_markdown\(sbom\)|read_bytes|byte-for-byte|assertEqual|actual_attribution)' \
  scripts/test_render_third_party_attribution.py

Length of output: 204005


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo='ContextualWisdomLab/clearfolio'
head='ed3863209109cd24a3cf1f1d6bdcd51db16fbef1'

printf '%s\n' '== Active exact-head checks =='
gh api "repos/$repo/commits/$head/check-runs?per_page=100" \
  --jq '[.check_runs[] | select(.status != "completed") | {name,status,conclusion,app:.app.slug,details_url,started_at}]'

printf '%s\n' '== User-identified exact-head workflow runs =='
for run in 31146875930 31146875953 31146875908 31146875907; do
  gh api "repos/$repo/actions/runs/$run" \
    --jq '{id,name,event,status,conclusion,head_sha,run_attempt,created_at,updated_at,html_url}'
done

printf '%s\n' '== Netty PURL and dependency coherence =='
python3 - <<'PY'
import json
from pathlib import Path

path = Path("docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json")
bom = json.loads(path.read_text(encoding="utf-8"))
netty = [c for c in bom["components"] if c.get("group") == "io.netty"]
refs = {c["bom-ref"] for c in netty}
edge_refs = {
    ref
    for dependency in bom["dependencies"]
    for ref in [dependency.get("ref"), *dependency.get("dependsOn", [])]
    if isinstance(ref, str) and ref.startswith("pkg:maven/io.netty/")
}
expected = "4.1.136.Final"
print("count=", len(netty))
print("versions=", sorted({c.get("version") for c in netty}))
print("purl_equals_bom_ref=", all(c.get("purl") == c.get("bom-ref") for c in netty))
print("purl_has_expected_version=", all(f"@{expected}" in c.get("purl", "") for c in netty))
print("netty_edge_refs_equal_component_refs=", edge_refs == refs)
for component in netty:
    print(component["purl"], component["bom-ref"])
PY

printf '%s\n' '== Repository attribution and Netty validation test =='
sed -n '100,200p' scripts/test_render_third_party_attribution.py

printf '%s\n' '== Current PR merge and review state =='
gh pr view 270 --repo "$repo" \
  --json headRefOid,mergeStateStatus,reviewDecision,reviews \
  --jq '{headRefOid,mergeStateStatus,reviewDecision,reviews:[.reviews[]|{author:.author.login,state,commit:.commit.oid}]}'

Length of output: 10327


@seonghobae I completed the independent review of exact head ed3863209109cd24a3cf1f1d6bdcd51db16fbef1.

I found no actionable source-level finding.

  • scripts/test_ci_workflow_stack_coverage.py now uses unittest.TestCase.
  • The test remains compatible with pytest.
  • Standard unittest discovery can execute the test.
  • The test preserves all-base pull-request coverage and exact-head versus synthetic-merge assertions.

The security controls remain correct.

  • downloadArtifact(...) requires artifact:read before job lookup.
  • The controller verifies tenant ownership before artifact access.
  • Cross-tenant access returns 404.
  • The authorization tests verify missing claims, missing artifact:read, cross-tenant concealment, and owned access.
  • AuditKeySeparationGuard enforces strong and distinct policy and audit keys.
  • Direct DefaultDocumentValidationService construction uses the same fail-closed validation as Spring startup.
  • Audit logs use a domain-separated, versioned HMAC approver fingerprint and a token fingerprint.
  • The captured-log test excludes the raw approver identifier and approval token.

The evidence controls remain correct.

  • The report gate bounds each report read to 16 MiB plus one overflow byte.
  • The report gate accepts UTF-8 with an optional BOM.
  • The report gate rejects NUL, DTD, entity declarations, malformed XML, missing or negative counts, zero tests, skips, failures, and errors.
  • JaCoCo rejects missed production lines and branches.
  • Maven Javadoc enables doclint=all, failOnError, and failOnWarnings.
  • The SBOM contains 61 components and 17 io.netty components.
  • All Netty components use 4.1.136.Final.
  • Netty PURLs equal their BOM references and include the reviewed version.
  • Netty dependency references equal the Netty component references.
  • The attribution test requires renderer output to equal the committed attribution.

The named exact-head workflow runs completed successfully:

  • CI 31146875930
  • Security Scan 31146875953
  • SAST Semgrep 31146875908
  • fuzz 31146875907

However, the current exact-head strix check is still in_progress. GitHub also reports mergeStateStatus=BLOCKED and reviewDecision=REVIEW_REQUIRED.

I do not submit APPROVE. The active strix check, the required repository protections, and a counted independent repository-write-authorized approval must complete before merge.

You are interacting with an AI system.

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@opencode-agent @cwl-noema-review Independently review exact current head ed3863209109cd24a3cf1f1d6bdcd51db16fbef1 only. Exact-head CI 31146875930, Security Scan 31146875953, SAST 31146875908, and fuzz 31146875907 are successful; Maven executed 476 tests with zero failures/errors/skips, verified zero missed production lines/branches across 59 production classes, completed warning-free public Javadocs, and passed synthetic-merge compatibility and buyer-readiness scripts. Revalidate the final 73-file authoritative parent: audit HMAC pseudonymization/key separation, Netty 4.1.136.Final alignment, deterministic CycloneDX/attribution evidence, fail-closed Surefire/Failsafe XML parsing, all-PR-base exact-head CI trigger, direct-download artifact:read authorization before lookup, tenant concealment, action pinning, least-privilege permissions, and absence of source-level blockers. Treat all predecessor reviews as stale. Submit a formal current-head review or path-specific actionable finding only. Do not infer the counted independent repository-write approval required by branch protection.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo='ContextualWisdomLab/clearfolio'
pr='270'
head='ed3863209109cd24a3cf1f1d6bdcd51db16fbef1'

printf '%s\n' '== Exact PR and check state =='
git cat-file -t "$head"
git show -s --format='head=%H%nparents=%P%nsubject=%s' "$head"
gh pr view "$pr" --repo "$repo" \
  --json headRefOid,baseRefOid,mergeStateStatus,reviewDecision,reviews \
  --jq '{headRefOid,baseRefOid,mergeStateStatus,reviewDecision,reviews:[.reviews[]|{author:.author.login,state,commit:.commit.oid}]}'
gh api "repos/$repo/commits/$head/check-runs?per_page=100" \
  --jq '[.check_runs[] | {name,status,conclusion,app:.app.slug,details_url}]'
gh api graphql -F owner='ContextualWisdomLab' -F name='clearfolio' -F number="$pr" -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) { nodes { isResolved } }
    }
  }
}' --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length'

printf '%s\n' '== Requested-head delta and CI discovery test =='
git diff --name-status "${head}^" "$head"
ast-grep outline scripts/test_ci_workflow_stack_coverage.py --items all --view expanded
sed -n '1,240p' scripts/test_ci_workflow_stack_coverage.py
rg -n -C 10 \
  '(pull_request:|merge_group:|pull_request\.head\.sha|github\.sha|actions/checkout|persist-credentials|permissions:|mvn -B --no-transfer-progress verify|verify_maven_test_reports|unittest discover|pytest)' \
  .github/workflows/ci.yml .github/workflows/fuzz.yml

printf '%s\n' '== Artifact authorization and audit controls =='
rg -n -C 22 --glob '*.java' \
  '(downloadArtifact|ARTIFACT_READ|conversionService\.getJob|requireSameTenant|artifactStore\.getPdf|AuditKeySeparationGuard\.validate|HmacSHA256|approverFingerprint|tokenFingerprint)' \
  src/main/java src/test/java
sed -n '1,260p' src/main/java/com/clearfolio/viewer/security/AuditKeySeparationGuard.java
sed -n '1,280p' src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java
sed -n '1,280p' scripts/verify_maven_test_reports.py

printf '%s\n' '== Build and workflow enforcement =='
rg -n -C 8 \
  '(netty.version|4\.1\.136\.Final|jacoco-maven-plugin|MISSEDCOUNT|maven-javadoc-plugin|doclint|failOnWarnings|failOnError)' \
  pom.xml
rg -n -C 4 \
  '(contents:\s*write|pull-requests:\s*write|issues:\s*write|id-token:\s*write|git push|gh (pr|api|issue)|curl .*(-X|--request) *(POST|PUT|PATCH|DELETE))' \
  .github/workflows || true

printf '%s\n' '== SBOM and attribution invariants =='
python3 - <<'PY'
import json
from pathlib import Path

path = Path("docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json")
bom = json.loads(path.read_text(encoding="utf-8"))
components = bom["components"]
refs = {c["bom-ref"] for c in components}
netty = [c for c in components if c.get("group") == "io.netty"]
netty_refs = {c["bom-ref"] for c in netty}
sources = {d["ref"] for d in bom["dependencies"]}
targets = {t for d in bom["dependencies"] for t in d.get("dependsOn", [])}
metadata_ref = bom["metadata"]["component"].get("bom-ref")
print("component_count=", len(components))
print("netty_component_count=", len(netty))
print("netty_versions=", sorted({c["version"] for c in netty}))
print("netty_purl_ref_version_coherent=", all(
    c["purl"] == c["bom-ref"] and "`@4.1.136.Final`" in c["purl"] for c in netty))
print("netty_edges_complete=", netty_refs <= sources and netty_refs <= targets)
print("only_metadata_non_component_refs=", (sources - refs | targets - refs) <= {metadata_ref})
print("legacy_netty_present=", "4.1.135.Final" in path.read_text(encoding="utf-8"))
PY
rg -n -C 8 \
  '(render_markdown\(sbom\)|read_bytes|byte-for-byte|assertEqual|actual_attribution)' \
  scripts/test_render_third_party_attribution.py

Length of output: 204347


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo='ContextualWisdomLab/clearfolio'
pr='270'
head='ed3863209109cd24a3cf1f1d6bdcd51db16fbef1'

printf '%s\n' '== Exact current GitHub state =='
gh pr view "$pr" --repo "$repo" \
  --json headRefOid,mergeStateStatus,reviewDecision,reviews \
  --jq '{headRefOid,mergeStateStatus,reviewDecision,reviews:[.reviews[]|{author:.author.login,state,commit:.commit.oid}]}'
gh api "repos/$repo/commits/$head/check-runs?per_page=100" \
  --jq '[.check_runs[] | {name,status,conclusion,app:.app.slug}]'
gh api graphql -F owner='ContextualWisdomLab' -F name='clearfolio' -F number="$pr" -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) { nodes { isResolved } }
    }
  }
}' --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length'

printf '%s\n' '== CI discovery regression test =='
cat -n scripts/test_ci_workflow_stack_coverage.py

printf '%s\n' '== CI trigger and revision controls =='
sed -n '1,260p' .github/workflows/ci.yml | nl -ba
sed -n '1,180p' .github/workflows/fuzz.yml | nl -ba

printf '%s\n' '== Direct-download authorization regressions =='
rg -n -C 14 --glob 'ConversionDownloadAuthorizationTest.java' \
  '(downloadRejects|downloadConceals|downloadReturns|verifyNoInteractions|verify\(.*getPdf|ARTIFACT_READ|JOB_READ)' \
  src/test/java

printf '%s\n' '== Raw override identifiers in production log calls =='
rg -n -P -C 5 --glob '*.java' \
  '(LOGGER|logger|LOG)\.(trace|debug|info|warn|error)\s*\(' \
  src/main/java/com/clearfolio/viewer/service/DefaultDocumentValidationService.java

Length of output: 10957


@seonghobae I reviewed exact head ed3863209109cd24a3cf1f1d6bdcd51db16fbef1 only.

I found no actionable source-level blocker.

  • scripts/test_ci_workflow_stack_coverage.py now uses unittest.TestCase.

  • Standard unittest discovery can execute the test.

  • The test requires pull_request: {}.

  • The test rejects the old main-only trigger.

  • The test preserves the exact-head checkout assertion and the synthetic-merge job markers.

  • ConversionController.downloadArtifact(...) requires artifact:read before job lookup.

  • A caller with only job:read is rejected before job or artifact access.

  • The controller checks tenant ownership before ArtifactStore.getPdf(...).

  • A cross-tenant request returns 404 and does not read the artifact.

  • AuditKeySeparationGuard requires a policy key with at least 32 UTF-8 bytes.

  • Enabled policy signing requires a dedicated audit key.

  • The guard rejects equal policy and audit key values.

  • Spring construction and direct DefaultDocumentValidationService construction use the same validation.

  • AuditPseudonymizer uses versioned, domain-separated HmacSHA256 fingerprints.

  • The accepted override audit event uses approverFingerprint and tokenFingerprint, not the raw approver identifier or approval token.

  • The Maven report gate reads each report with a 16 MiB limit plus one overflow byte.

  • The gate accepts UTF-8 with an optional BOM.

  • The gate rejects NUL bytes, DTD and entity declarations, malformed XML, missing or negative counts, zero tests, skips, failures, and errors.

  • JaCoCo rejects missed production lines and branches.

  • Maven Javadoc uses doclint=all, failOnError=true, and failOnWarnings=true.

  • The POM pins Netty to 4.1.136.Final.

  • The SBOM contains 61 components and 17 io.netty components at that version.

  • Netty PURLs, BOM references, and dependency edges are coherent.

  • The attribution test requires generated output to equal the committed attribution.

  • I found no write-scoped workflow permission or repository mutation command.

The named exact-head CI, merge-compatibility, buyer-readiness, security, Semgrep, fuzz, and Strix checks are successful. The PR has zero unresolved review threads. I did not count skipped, cancelled, failed, or predecessor results as passing evidence.

I do not submit APPROVE. GitHub currently reports mergeStateStatus=BLOCKED and reviewDecision=REVIEW_REQUIRED. A counted independent repository-write-authorized approval and all required branch protections remain necessary before merge.

You are interacting with an AI system.

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.

2 participants