🛡️ Sentinel: [CRITICAL/HIGH] Fix PII exposure in policy override logs - #165
🛡️ Sentinel: [CRITICAL/HIGH] Fix PII exposure in policy override logs#165seonghobae wants to merge 27 commits into
Conversation
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
Pull request was converted to draft
seonghobae
left a comment
There was a problem hiding this comment.
The plaintext-log finding is valid, but unkeyed truncated SHA-256 is not sufficient pseudonymization for low-entropy approver identifiers: an operator with log access can dictionary-attack likely usernames, employee IDs, or email addresses. Keep this PR draft and use a domain-separated keyed HMAC with a dedicated audit-pseudonym secret, not the approval-token signing secret. Requirements:
- Normalize the identifier under a documented, stable rule before HMAC only if identity semantics require it; otherwise preserve exact bytes.
- Include an explicit domain/version prefix such as
clearfolio:audit-approver:v1to prevent cross-protocol correlation. - Rename the structured field from
approverIdtoapproverFingerprintso downstream consumers do not mistake it for plaintext. - Fail closed or emit a non-correlatable sentinel when the dedicated key is unavailable; never fall back to raw identifiers or unkeyed hashing.
- Do not log
null; use a fixed absent marker and distinguish absent from empty input. - Add tests for determinism within a key version, separation across keys/domains, absent/empty handling, Unicode identifiers, control characters, key rotation, and proof that neither the raw identifier nor token appears in captured logs.
- Document retention, key ownership/rotation, incident response, and the fact that pseudonymized data remains personal data in many privacy regimes.
Re-run exact-head CI, 100% production statement/branch coverage, SAST, security scans, and independent review after the privacy contract is corrected.
|
@jules Please address review 4859473107: replace unkeyed SHA-256 with domain-separated keyed HMAC using a dedicated audit pseudonym key, rename the log field, add rotation/absence/privacy tests, and update operator documentation. Keep draft until all exact-head gates pass. |
d8408bb to
2775bd6
Compare
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthrough감사 로그의 승인자 식별자와 승인 토큰을 지문으로 대체했습니다. 전용 키, 키 버전, 도메인 분리, 키 부재 표식을 추가했습니다. 설정, 키 검증, 서비스 연동, 테스트 및 보안 문서를 갱신했습니다. Changes감사 식별자 의사익명화
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant DefaultDocumentValidationService
participant AuditPseudonymizer
participant AuditLogger
DefaultDocumentValidationService->>AuditPseudonymizer: 승인자 식별자 전달
AuditPseudonymizer-->>DefaultDocumentValidationService: 승인자 지문 또는 unavailable 반환
DefaultDocumentValidationService->>AuditLogger: 지문과 토큰 지문을 포함한 감사 메시지 기록
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
|
@opencode-agent Please independently review the exact current head |
I have replaced the unkeyed SHA-256 with a domain-separated keyed HMAC using a dedicated |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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/security/AuditPseudonymizer.java`:
- Around line 95-113: Update normalizeKeyVersion in AuditPseudonymizer so
DEFAULT_KEY_VERSION is used only when keyVersion is absent; explicit blank,
oversized, or unsafe values must be rejected during startup rather than
converted to v1. Preserve validation of allowed characters and length, and
update the normalizesUnsafeOrMissingKeyVersionsToV1 test to assert rejection of
invalid explicit versions.
In
`@src/main/java/com/clearfolio/viewer/service/DefaultDocumentValidationService.java`:
- Around line 47-50: Update the initialization around
DefaultDocumentValidationService’s AuditPseudonymizer construction to reject
startup when the nonblank audit pseudonym secret and policy-override HMAC key
are identical, while preserving valid distinct-key initialization. Use separate
key configuration entries and add a regression test verifying that equal values
fail fast.
In `@src/main/resources/application.yml`:
- Around line 13-16: Remove the runtime environment-variable placeholders from
audit-pseudonym-secret and audit-pseudonym-key-version in application.yml.
Update the ConversionProperties/AuditPseudonymizer configuration flow to resolve
both values from the KV or credential registry, retaining environment variables
only for that store’s bootstrap initialization.
In `@src/test/java/com/clearfolio/viewer/security/AuditPseudonymizerTest.java`:
- Around line 56-65: Extend distinguishesAbsentEmptyAndUnavailableValues to
instantiate AuditPseudonymizer with a null secret and assert that
fingerprint("approver") returns "unavailable:v1", covering the cleanSecret null
branch while preserving the existing whitespace-secret assertions.
- Around line 103-121: Update the provider-removal setup in the
AuditPseudonymizer test to record each provider’s original 1-based position
before removal, then restore it in finally with
Security.insertProviderAt(provider, position) instead of
Security.addProvider(provider). If parallel test execution makes the global
provider registry unsafe, replace this failure injection with an approach that
does not mutate the JVM-wide registry.
🪄 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: 2441a409-c764-4962-984e-a70cbafd8566
📒 Files selected for processing (8)
CHANGELOG.mddocs/security/2026-08-04-audit-pseudonymization.mdsrc/main/java/com/clearfolio/viewer/config/ConversionProperties.javasrc/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.javasrc/main/java/com/clearfolio/viewer/service/DefaultDocumentValidationService.javasrc/main/resources/application.ymlsrc/test/java/com/clearfolio/viewer/security/AuditPseudonymizerTest.javasrc/test/java/com/clearfolio/viewer/service/DefaultDocumentValidationServiceAuditTest.java
|
@jules Continue from exact current head
Do not weaken HMAC domain separation, absent/unavailable semantics, key separation, captured-log privacy assertions, or existing review-agent credentials. |
|
Current-head disposition for the two remaining CodeRabbit findings:
The PR remains draft while the new exact head completes CI, coverage, SAST, security, fuzz, CodeRabbit re-review, and independent review. |
|
@coderabbitai review @opencode-agent Please independently review exact current head |
|
|
|
@opencode-agent Please independently review exact current head |
|
@coderabbitai review |
|
|
@opencode-agent The RED head Fix this in the same bounded GREEN change. Prefer a dependency-free, fail-closed parser for this repository-owned contract—for example, read the UTF-8 POM text and require exactly one non-blank Then regenerate the SBOM and attribution from the resolved Maven graph, run the full script suite, |
|
@opencode-agent @cwl-noema-review Continue the current exact-head review→fix→verify loop without assuming the previously referenced SHA is still current. First inspect the live branch head, latest comments, reviews, and every required check. If the test-first buyer-evidence contract is still RED, regenerate the CycloneDX SBOM from the resolved Maven graph, regenerate the third-party attribution from that SBOM, and preserve the coherent Spring-managed Netty 4.1.136.Final family. Do not hand-edit generated metadata, weaken the renderer/contract test, lower JaCoCo or Javadoc gates, suppress security findings, or alter unrelated privacy behavior. Run the full repository acceptance lifecycle, then verify CI, Security Scan, SAST, all fuzz jobs, Strix/repository-policy checks, automated review, and zero unresolved threads on the exact resulting head. If the current head is already GREEN, avoid a no-op commit and instead update stale PR evidence and request counted independent approval. Keep auto-merge disabled until every exact-head technical gate is successful; once successful, mark Ready and enable protected auto-merge without bypassing independent approval. |
|
@coderabbitai review Review the live exact current head only. Re-check the resolved Netty dependency graph, regenerated CycloneDX SBOM, generated third-party attribution, deterministic evidence contract, audit-pseudonym privacy guarantees, config-tree secret handling, warning-free public Javadocs, 100% production line/branch coverage, CI, Security Scan, SAST, fuzz, and repository-policy evidence. Distinguish current blockers from stale findings on superseded heads. Do not recommend merge while any current-head required result is queued, pending, skipped-required, failed, cancelled, stale, or while independent write-authorized approval is absent. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
repo="ContextualWisdomLab/clearfolio"
echo '== Live PR identity and state =='
gh pr view 165 --repo "$repo" \
--json number,headRefOid,baseRefName,isDraft,mergeStateStatus,reviewDecision,statusCheckRollup,reviews,latestReviews
echo '== Checked-out identity and changed paths =='
printf 'HEAD: '; git rev-parse HEAD
base="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main)"
printf 'Merge base: '; git rev-parse "$base"
git diff --name-status "$base"...HEAD
echo '== Dependency-management and generated-evidence locations =='
for file in \
pom.xml \
docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json \
docs/legal/2026-07-03-third-party-attribution.md \
scripts/render_third_party_attribution.py \
scripts/test_render_third_party_attribution.py \
src/test/java/com/clearfolio/viewer/config/DependencyPolicyTest.java \
docs/security/2026-08-05-netty-4.1.136-remediation.md \
CHANGELOG.md
do
if [ -f "$file" ]; then
echo "--- $file"
cat -n "$file"
fi
done
echo '== Netty declarations and committed evidence references =='
rg -n -i -C 4 \
'netty\.version|io\.netty|4\.1\.13[0-9]\.Final|dependency:tree|CycloneDX|SBOM|attribution' \
pom.xml src/test scripts docs CHANGELOG.md .github 2>/dev/null || true
echo '== Parse SBOM Netty component and dependency consistency =='
python3 - <<'PY'
import json
from pathlib import Path
p = Path("docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json")
data = json.loads(p.read_text(encoding="utf-8"))
components = data.get("components", [])
netty = [c for c in components if c.get("group") == "io.netty" or "pkg:maven/io.netty/" in c.get("purl", "")]
print("netty_components=", len(netty))
for c in netty:
print(json.dumps({
"name": c.get("name"), "version": c.get("version"),
"purl": c.get("purl"), "bom-ref": c.get("bom-ref"),
"hashes": c.get("hashes")
}, sort_keys=True))
refs = {c.get("bom-ref") for c in netty}
for dep in data.get("dependencies", []):
ref = dep.get("ref", "")
depends = dep.get("dependsOn", [])
if ref in refs or any(d in refs for d in depends):
print("netty_dependency_edge=", json.dumps(dep, sort_keys=True))
PY
echo '== Security and privacy implementation outlines =='
for file in \
src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java \
src/main/java/com/clearfolio/viewer/security/AuditKeySeparationGuard.java \
src/main/java/com/clearfolio/viewer/config/ConversionProperties.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentValidationService.java \
src/main/java/com/clearfolio/viewer/service/PolicyOverrideRequest.java
do
if [ -f "$file" ]; then
echo "--- $file"
ast-grep outline "$file" --view expanded
fi
done
echo '== Privacy configuration, logging, and focused tests =='
for file in \
src/main/resources/application.yml \
src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java \
src/main/java/com/clearfolio/viewer/security/AuditKeySeparationGuard.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentValidationService.java \
src/main/java/com/clearfolio/viewer/service/PolicyOverrideRequest.java \
src/test/java/com/clearfolio/viewer/security/AuditPseudonymizerTest.java \
src/test/java/com/clearfolio/viewer/security/AuditPseudonymizerKeyStrengthTest.java \
src/test/java/com/clearfolio/viewer/security/AuditKeySeparationGuardTest.java \
src/test/java/com/clearfolio/viewer/service/DefaultDocumentValidationServiceAuditTest.java \
src/test/java/com/clearfolio/viewer/service/PolicyOverrideRequestTest.java
do
if [ -f "$file" ]; then
echo "--- $file"
cat -n "$file"
fi
done
echo '== Coverage, Javadoc, and immutable workflow contract =='
rg -n -C 8 'jacoco|LINE|BRANCH|javadoc|doclint|maven-javadoc|actions/checkout|@' \
pom.xml .github 2>/dev/null || true
echo '== Workflows for the live head =='
sha="$(gh pr view 165 --repo "$repo" --json headRefOid --jq .headRefOid)"
gh run list --repo "$repo" --commit "$sha" --limit 100 \
--json databaseId,name,workflowName,status,conclusion,headSha,event,url
echo '== Active rulesets and branch protection =='
gh api "repos/$repo/rulesets" 2>&1 || true
gh api "repos/$repo/branches/main/protection" 2>&1 || true
echo '== Unresolved, non-outdated review threads =='
gh api graphql -F owner="ContextualWisdomLab" -F name="clearfolio" -F number=165 -f query='
query($owner: String!, $name: String!, $number: Int!) {
repository(owner: $owner, name: $name) {
pullRequest(number: $number) {
reviewThreads(first: 100) {
nodes {
isResolved
isOutdated
path
line
comments(first: 1) { nodes { author { login } body } }
}
}
}
}
}' --jq '.data.repository.pullRequest.reviewThreads.nodes
| map(select((.isResolved | not) and (.isOutdated | not)))
| map({path,line,author: .comments.nodes[0].author.login,body: .comments.nodes[0].body})' 2>&1 || trueLength of output: 205509 🏁 Script executed: #!/bin/bash
set -euo pipefail
repo="ContextualWisdomLab/clearfolio"
log="/tmp/coderabbit-shell-logs/shell-output-9jJ2IT"
echo '== Compact live PR state from the prior inspection =='
sed -n '1,220p' "$log"
echo '== Current exact head, merge base, and changed files =='
live="$(gh pr view 165 --repo "$repo" --json headRefOid --jq .headRefOid)"
printf 'Live head: %s\n' "$live"
printf 'Checked-out head: '; git rev-parse HEAD
base="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main)"
printf 'Merge base: '; git rev-parse "$base"
git diff --name-status "$base...$live"
echo '== Current evidence files: Netty values and provenance =='
rg -n -C 2 '4\.1\.13[56]\.Final|generated|Generated|source|Source|head|commit|SBOM|CycloneDX' \
docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json \
docs/legal/2026-07-03-third-party-attribution.md \
docs/security/2026-08-05-netty-4.1.136-remediation.md \
CHANGELOG.md
echo '== Exact deterministic evidence contract =='
for file in \
scripts/test_render_third_party_attribution.py \
scripts/render_third_party_attribution.py \
src/test/java/com/clearfolio/viewer/config/DependencyPolicyTest.java
do
echo "--- $file"
cat -n "$file"
done
echo '== Evidence contracts that mention Netty or current SBOM consistency =='
rg -n -C 4 -i \
'netty|4\.1\.136|4\.1\.135|sbom|attribution|drift|pom' \
scripts src/test/java .github/workflows/ci.yml
echo '== One-shot workflow diff and result details =='
git diff --unified=30 "$base...$live" -- .github/workflows/one-shot-netty-sbom-refresh.yml
gh run view 31004040777 --repo "$repo" --log 2>&1 \
| rg -n -C 5 'HEAD|3b6e434|cyclonedx|SBOM|attribution|4\.1\.13[56]|artifact|success|failure' \
|| true
echo '== Expanded active rulesets =='
for id in 18156473 13042993; do
echo "--- ruleset $id"
gh api "repos/$repo/rulesets/$id" 2>&1 || true
done
echo '== Current exact-head status summary, reviews, and required approvals =='
gh pr view 165 --repo "$repo" \
--json headRefOid,mergeStateStatus,reviewDecision,isDraft,reviews,latestReviews,statusCheckRollup \
--jq '{
headRefOid, mergeStateStatus, reviewDecision, isDraft,
incomplete: [.statusCheckRollup[] | select(.status != "COMPLETED" or (.conclusion != "SUCCESS" and .conclusion != "SKIPPED")) | {name,status,conclusion,workflowName}],
failures: [.statusCheckRollup[] | select(.conclusion == "FAILURE" or .conclusion == "CANCELLED") | {name,status,conclusion,workflowName}],
latestReviews
}'Length of output: 220717
I found two current blockers.
I verified these current source controls:
I cannot verify successful current-head CI, Javadocs, coverage, Security Scan, SAST, fuzzing, CodeQL, Strix, or required reviews. Those checks are queued or in progress. GitHub reports You are interacting with an AI system. |
|
@opencode-agent The corrected read-only evidence run Its manifest records:
Complete the bounded handoff now:
After the cleanup head exists, request fresh exact-head CodeRabbit/OpenCode/Noema review. No previous-head check may be counted as merge evidence. |
|
@opencode-agent STOP before cleanup/claiming success: commit The current branch blob Use the exact downloaded artifact file whose SHA-256 is Required correction:
Do not amend the test to accept an empty SBOM, do not hand-edit the artifact, and do not treat the workflow's success as proof of the currently committed file. |
|
@opencode-agent Continue the valid current-head generated-evidence repair on exact head The read-only exact-head generation run
The run independently proved every Netty component purl and bom-ref, and every Netty dependency reference, uses Required final bounded commit:
After committing, run |
Pull request was converted to draft
|
@opencode-agent The attempted repair on current draft head Current committed Use the already successful read-only artifact Before committing, assert 61 total components, 17 |
|
@coderabbitai review @opencode-agent @cwl-noema-review Please independently review only exact current head |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
repo="ContextualWisdomLab/clearfolio"
expected="dea088c77109cfa6cb20e3e22fd543b045ddc192"
echo "== Exact identity and working tree =="
printf 'HEAD: '; git rev-parse HEAD
printf 'Expected object: '; git cat-file -t "$expected"
git merge-base --is-ancestor "$expected" HEAD \
&& echo "Expected commit reachable from HEAD" \
|| echo "Expected commit NOT reachable from HEAD"
git status --short
echo "== PR current head =="
gh pr view 165 --repo "$repo" \
--json headRefOid,isDraft,mergeStateStatus,reviewDecision,statusCheckRollup,reviews,latestReviews,baseRefName
echo "== Merge base and changed paths =="
base="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main)"
printf 'Merge base: '; git rev-parse "$base"
git diff --name-status "$base"...HEAD
echo "== Generated-evidence presence and Netty consistency =="
python3 - <<'PY'
import hashlib
import json
import re
from pathlib import Path
pom = Path("pom.xml").read_text(encoding="utf-8")
matches = re.findall(r"<netty\.version>\s*([^<\s]+)\s*</netty\.version>", pom)
print("pom_netty_version_matches=", matches)
sbom_path = Path("docs/qa/evidence/2026-07-02-krw2b-sale-readiness/sbom-cyclonedx.json")
attr_path = Path("docs/legal/2026-07-03-third-party-attribution.md")
for path in (sbom_path, attr_path):
raw = path.read_bytes()
print(f"{path}_sha256={hashlib.sha256(raw).hexdigest()}")
print(f"{path}_git_blob=", end="")
# Print a Git-compatible blob ID without modifying the repository.
import subprocess
print(subprocess.check_output(["git", "hash-object", str(path)], text=True).strip())
sbom_text = sbom_path.read_text(encoding="utf-8")
sbom = json.loads(sbom_text)
components = sbom.get("components", [])
netty = [c for c in components if c.get("group") == "io.netty" or "pkg:maven/io.netty/" in c.get("purl", "")]
print("sbom_component_count=", len(components))
print("sbom_netty_component_count=", len(netty))
print("sbom_netty_versions=", sorted({c.get("version") for c in netty}))
print("sbom_contains_4.1.135.Final=", "4.1.135.Final" in sbom_text)
print("attribution_contains_4.1.135.Final=", "4.1.135.Final" in attr_path.read_text(encoding="utf-8"))
print("attribution_contains_4.1.136.Final=", "4.1.136.Final" in attr_path.read_text(encoding="utf-8"))
refs = {c.get("bom-ref") for c in netty}
edges = [d for d in sbom.get("dependencies", []) if d.get("ref") in refs or any(x in refs for x in d.get("dependsOn", []))]
print("sbom_netty_dependency_edge_count=", len(edges))
for component in netty:
print("netty_component=", json.dumps({k: component.get(k) for k in ("name", "version", "purl", "bom-ref")}, sort_keys=True))
PY
echo "== Temporary workflow presence =="
if [ -e .github/workflows/one-shot-netty-sbom-refresh.yml ]; then
echo "TEMPORARY_WORKFLOW_PRESENT"
cat -n .github/workflows/one-shot-netty-sbom-refresh.yml
else
echo "TEMPORARY_WORKFLOW_ABSENT"
fi
echo "== Evidence contract map =="
for file in \
scripts/test_render_third_party_attribution.py \
scripts/render_third_party_attribution.py \
src/test/java/com/clearfolio/viewer/config/DependencyPolicyTest.java \
docs/security/2026-08-05-netty-4.1.136-remediation.md \
pom.xml
do
if [ -f "$file" ]; then
echo "--- $file"
ast-grep outline "$file" --view expanded 2>/dev/null || true
rg -n -C 4 'netty|SBOM|attribution|version|CycloneDX|component|dependency' "$file" || true
fi
done
echo "== Privacy and secret-source implementation map =="
for file in \
src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java \
src/main/java/com/clearfolio/viewer/security/AuditKeySeparationGuard.java \
src/main/java/com/clearfolio/viewer/config/ConversionProperties.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentValidationService.java \
src/main/java/com/clearfolio/viewer/service/PolicyOverrideRequest.java \
src/main/resources/application.yml \
src/test/java/com/clearfolio/viewer/security/AuditPseudonymizerTest.java \
src/test/java/com/clearfolio/viewer/security/AuditKeySeparationGuardTest.java \
src/test/java/com/clearfolio/viewer/service/DefaultDocumentValidationServiceAuditTest.java
do
if [ -f "$file" ]; then
echo "--- $file"
rg -n -C 4 'HmacSHA256|32|UTF-8|fingerprint|approver|approvalToken|unavailable|absent|configtree|secret|key.version|redact|toString' "$file" || true
fi
done
echo "== Coverage, Javadoc, and workflow policy =="
rg -n -C 6 'jacoco|LINE|BRANCH|javadoc|doclint|maven-javadoc|actions/checkout|dependency:tree' pom.xml .github 2>/dev/null || true
echo "== Same-head workflow runs =="
gh run list --repo "$repo" --commit "$expected" --limit 100 \
--json databaseId,name,workflowName,status,conclusion,headSha,event,url
echo "== Rulesets and unresolved review threads =="
gh api "repos/$repo/rulesets" 2>&1 || true
gh api graphql -F owner="ContextualWisdomLab" -F name="clearfolio" -F number=165 -f query='
query($owner: String!, $name: String!, $number: Int!) {
repository(owner: $owner, name: $name) {
pullRequest(number: $number) {
reviewThreads(first: 100) {
nodes {
isResolved
isOutdated
path
line
comments(first: 1) { nodes { author { login } body } }
}
}
}
}
}' --jq '.data.repository.pullRequest.reviewThreads.nodes
| map(select((.isResolved | not) and (.isOutdated | not)))
| map({path,line,author: .comments.nodes[0].author.login,body: .comments.nodes[0].body})' 2>&1 || trueLength of output: 99000
The requested commit I found a blocker in
Replace the empty SBOM with the verified generated artifact. Regenerate or byte-compare the attribution from that SBOM. Do not weaken the evidence contract. I verified that All workflows for Please request a new review for live head You are interacting with an AI system. |
2f791b8 to
6e311ed
Compare
|
Superseded by #267. This branch repeatedly received unrelated Netty/SBOM commits and write-scoped self-mutating workflows after the reviewed exact head, so its head could not remain stable enough for trustworthy exact-head acceptance. The reviewed tree at |
|
Closing as superseded by clean replacement #267. This branch moved beyond its last reviewed privacy head and accumulated unrelated Netty/SBOM evidence and write-scoped self-mutating workflow commits. #267 is pinned to the last technically accepted privacy tree |
|
Closed-unmerged PR #165 is superseded by draft #270, which uses the same current branch at exact head |
|
Closing as superseded by clean replacement #267. This branch repeatedly accumulated unrelated Netty/SBOM and write-scoped repair commits after reviewed privacy heads. #267 preserves the bounded audit-pseudonymization tree on protected |
|
@coderabbitai review Please review exact current head @opencode-agent Review this exact head after current-head Strix and repository checks are clean. @cwl-noema-review Independently review this exact head; predecessor-head Strix findings must not be reused as approval evidence. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
repo="ContextualWisdomLab/clearfolio"
expected="ac70dd738acea7eeb311916eda1b2fa8f3782c82"
echo '== Commit and PR identity =='
printf 'Checked-out HEAD: '; git rev-parse HEAD
printf 'Requested object type: '; git cat-file -t "$expected"
gh pr view 165 --repo "$repo" \
--json state,headRefOid,isDraft,mergeStateStatus,reviewDecision,statusCheckRollup,reviews,latestReviews,baseRefName
echo '== Requested commit ancestry and diff scope =='
git merge-base --is-ancestor "$expected" HEAD && echo 'requested_commit_reachable=true' || echo 'requested_commit_reachable=false'
base="$(git merge-base "$expected" origin/main 2>/dev/null || git merge-base "$expected" main)"
printf 'Merge base: '; git rev-parse "$base"
git diff --name-status "$base...$expected"
echo '== Security implementation and configuration =='
for file in \
src/main/java/com/clearfolio/viewer/security/AuditPseudonymizer.java \
src/main/java/com/clearfolio/viewer/security/AuditKeySeparationGuard.java \
src/main/java/com/clearfolio/viewer/config/ConversionProperties.java \
src/main/java/com/clearfolio/viewer/service/DefaultDocumentValidationService.java \
src/main/java/com/clearfolio/viewer/service/PolicyOverrideRequest.java \
src/main/resources/application.yml
do
if [ -f "$file" ]; then
echo "--- $file"
cat -n "$file"
fi
done
echo '== Focused privacy tests and operator documentation =='
for file in \
src/test/java/com/clearfolio/viewer/security/AuditPseudonymizerTest.java \
src/test/java/com/clearfolio/viewer/security/AuditPseudonymizerKeyStrengthTest.java \
src/test/java/com/clearfolio/viewer/security/AuditKeySeparationGuardTest.java \
src/test/java/com/clearfolio/viewer/service/DefaultDocumentValidationServiceAuditTest.java \
src/test/java/com/clearfolio/viewer/service/PolicyOverrideRequestTest.java \
docs/security/2026-08-04-audit-pseudonymization.md \
docs/diagrams/submit-flow.md \
docs/diagrams/submit-policy-adapter-flow.md \
docs/prd/clearfolio-viewer-unified-document-preview-prd.md
do
if [ -f "$file" ]; then
echo "--- $file"
cat -n "$file"
fi
done
echo '== Sensitive logging and authentication-value references =='
rg -n -C 4 --type java \
'(logger|LOG|log)\.(trace|debug|info|warn|error)\s*\(|approverId\(\)|approvalToken\(\)|authentication.?token|Authorization|Bearer|approverFingerprint|tokenFingerprint' \
src/main/java src/test/java || true
echo '== JaCoCo, Javadoc, and workflow configuration =='
rg -n -C 8 'jacoco|LINE|BRANCH|javadoc|doclint|maven-javadoc|coverage' pom.xml .github 2>/dev/null || true
echo '== Exact-head workflow runs =='
gh run list --repo "$repo" --commit "$expected" --limit 100 \
--json databaseId,name,workflowName,status,conclusion,headSha,event,url
echo '== Rulesets and active unresolved review threads =='
gh api "repos/$repo/rulesets" 2>&1 || true
gh api graphql -F owner="ContextualWisdomLab" -F name="clearfolio" -F number=165 -f query='
query($owner: String!, $name: String!, $number: Int!) {
repository(owner: $owner, name: $name) {
pullRequest(number: $number) {
reviewThreads(first: 100) {
nodes {
isResolved
isOutdated
path
line
comments(first: 1) { nodes { author { login } body } }
}
}
}
}
}' --jq '.data.repository.pullRequest.reviewThreads.nodes
| map(select((.isResolved | not) and (.isOutdated | not)))
| map({path,line,author:.comments.nodes[0].author.login,body:.comments.nodes[0].body})' 2>&1 || trueLength of output: 188856 🏁 Script executed: #!/bin/bash
set -euo pipefail
repo="ContextualWisdomLab/clearfolio"
run="30987730213"
echo '== Strix run and job state =='
gh run view "$run" --repo "$repo" --json databaseId,headSha,status,conclusion,name,url,jobs
echo '== Strix failure log excerpts =='
gh run view "$run" --repo "$repo" --log-failed 2>&1 \
| rg -n -i -C 8 \
'error|fail|failure|denied|missing|timeout|rate limit|advisory|vulnerab|policy|exit code|strix' \
|| trueLength of output: 910
I found no new source-level blocker in the requested audit-pseudonymization controls. I verified:
I cannot approve this commit. PR Also, the requested commit’s same-head Strix workflow You are interacting with an AI system. |
I apologize, but as an AI agent operating in this sandbox, I do not have direct access to download artifacts from GitHub Actions runs (like artifact ID 8929593015 from run 31004040777). The |
Security objective
Remove raw policy-override approver identifiers from application logs without replacing them with dictionary-attackable unkeyed hashes, and prevent weak HMAC material from authorizing policy exceptions.
Changes
AuditPseudonymizerfor low-entropy audit identifiers.approverFingerprint=<key-version>:<128-bit hex>instead ofapproverId.absentand non-correlatableunavailablemarkers; never fall back to plaintext or an unkeyed identifier hash.v1, while rejecting every invalid explicit value—including blank, padded, oversized, and unsafe versions—without trimming it into a different valid identifier.approverFingerprintfield.CHANGELOG.mdinto one canonical[Unreleased]section with a single trailing newline.ConversionPropertiescontract.Test-first and review evidence
CodeRabbit identified three valid findings on
b3ad882680f81b2bbfeddac892ba71bb45af8ade: duplicate[Unreleased]changelog sections, an invalid trailing-newline contract, and an uncovered missing-policy-key startup branch. Commit0e7770be5de992a7d4e24f4626508682bf9d7232added the real-contract regression test first. Commita86ab46c3214c803a90f51deec3d4d8723699667then consolidated the changelog and fixed its end-of-file contract. All corresponding review threads are resolved.The previous Strix failure on
5261356ac34e6545bce947ba0bcf2b1ce9f9be67identified a valid weak-policy-key finding. The current implementation and documentation address that finding. An unrelated one-lineupdate_commit.shCI-trigger file was removed from the final diff.Exact head
c0c0c456701449cf42e0425dadd24fb4582f5951provided red acceptance evidence: all 467 tests passed, but the zero-missed-branch JaCoCo gate correctly failed on three branches. The final three commits remove two branches that are unreachable under the real configuration and filename-normalization contracts and extend the policy-override control-character regression test to exercise carriage-return sanitization. No coverage threshold was weakened.Exact-head evidence
Exact current head
6e311edd1c21f30eacbfcdb8d92a903e587c76d0is based directly on protectedmainatf3cc09a9838f0f88c81a2ceae22138fab80a2edband is mergeable.30997431473: succeeded, including Maven verification, zero missed production lines and branches, and public Javadoc validation.30997431452: succeeded.30997431538: succeeded.30997431455: succeeded.No queued, pending, cancelled, skipped-required, stale-head, or previous-head result is counted as passing.
Merge gate
Do not merge until an independent reviewer with repository write access approves exact head
6e311edd1c21f30eacbfcdb8d92a903e587c76d0, any required Strix/OpenCode/Noema evidence is successful for this exact head, and every branch-protection, security, coverage, review, and repository-policy gate is satisfied. Do not bypass protections or weaken tests.