docs(security): establish coordinated vulnerability disclosure - #72
docs(security): establish coordinated vulnerability disclosure#72seonghobae wants to merge 22 commits into
Conversation
|
Warning Review limit reached
Next review available in: 28 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 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthrough공개 보안 정책과 취약점 공개 지침을 추가했습니다. 접수부터 검증, 수정, 릴리스, 공개, 복구, 증거 보존까지의 처리 lifecycle을 정의했습니다. 관련 문서의 필수 내용을 검증하는 Vitest 계약 테스트를 추가했습니다. Changes취약점 공개 및 처리
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Reporter
participant GitHubPrivateReport
participant MaintainerLifecycle
participant ReleaseEvidence
Reporter->>GitHubPrivateReport: 비공개 취약점 신고와 재현 증거 제출
GitHubPrivateReport->>MaintainerLifecycle: 신고 접수 및 case identifier 생성
MaintainerLifecycle->>ReleaseEvidence: 검증, 수정, 테스트, 승인 증거 기록
ReleaseEvidence-->>MaintainerLifecycle: 릴리스·배포·복구 검증 결과 반환
MaintainerLifecycle-->>Reporter: 상태 업데이트와 조정된 공개 일정 전달
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
@coderabbitai review Please perform a substantive read-only review of exact current head |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
expected='d43b09386e5fd10aaf72882c9d34e3a9b6b3cc64'
actual="$(git rev-parse HEAD)"
printf 'HEAD=%s\nEXPECTED=%s\n' "$actual" "$expected"
if [ "$actual" != "$expected" ]; then
printf 'ERROR: checked-out revision does not match the requested exact head\n' >&2
exit 2
fi
printf '\n== Commit ==\n'
git show -s --format='%H%n%P%n%s' HEAD
printf '\n== Changed files versus parent ==\n'
git diff-tree --no-commit-id --name-status -r HEAD
printf '\n== Candidate policy/lifecycle files ==\n'
fd -HI -t f '^(SECURITY\.md|CHANGELOG\.md|.*[Ss]ecur.*\.(md|test\.(ts|js))|.*[Vv]ulnerab.*\.(md|test\.(ts|js)))$' . \
-E .git -E node_modules -E dist -E build | sort
printf '\n== Diff stat ==\n'
git diff --stat HEAD^ HEADLength of output: 1567 🏁 Script executed: #!/bin/bash
set -euo pipefail
base='9adb784902cae19a150146a8fadd6a0491f67814'
head='d43b09386e5fd10aaf72882c9d34e3a9b6b3cc64'
git cat-file -e "${base}^{commit}"
git cat-file -e "${head}^{commit}"
printf '%s\n' '== Files changed in the complete PR range =='
git diff --name-status "$base" "$head"
printf '%s\n' '== Complete PR diff =='
git diff --find-renames --find-copies --unified=40 "$base" "$head" -- \
SECURITY.md \
CHANGELOG.md \
docs/doctoring/vulnerability-disclosure.md \
docs/security/vulnerability-handling.md \
docs/security-validation-checklist.md \
test/security-policy-contract.test.ts \
test/security-checklist.test.ts \
test/security-validation-evidence.test.ts
printf '%s\n' '== Numbered relevant file contents at exact head =='
for f in \
SECURITY.md \
CHANGELOG.md \
docs/doctoring/vulnerability-disclosure.md \
docs/security/vulnerability-handling.md \
docs/security-validation-checklist.md \
test/security-policy-contract.test.ts \
test/security-checklist.test.ts \
test/security-validation-evidence.test.ts
do
if [ -f "$f" ]; then
printf '\n----- %s -----\n' "$f"
cat -n "$f"
fi
doneLength of output: 123710 🤖 web_search executed:
Length of output: 11929 🏁 Script executed: #!/bin/bash
set -euo pipefail
head='d43b09386e5fd10aaf72882c9d34e3a9b6b3cc64'
test "$(git rev-parse HEAD)" = "$head"
printf '%s\n' '== Policy-related claims at exact head =='
rg -n -i -C 2 \
'(private (vulnerability )?report|report a vulnerability|security (email|contact)|bug bounty|compensation|contractual SLA|24.?7|production.ready|supported version|security support|release readiness|deployment readiness|coordinated disclosure|CVE|CVSS|known exploited|safe harbor)' \
--glob '*.md' --glob '*.ts' --glob '*.js' --glob '*.mjs' \
-g '!node_modules/**' -g '!dist/**' -g '!build/**' .
printf '%s\n' '== Markdown links in new policy documents =='
python3 - <<'PY'
import re
from pathlib import Path
files = [
Path("SECURITY.md"),
Path("docs/security/vulnerability-handling.md"),
Path("docs/doctoring/vulnerability-disclosure.md"),
]
for path in files:
print(f"\n{path}:")
text = path.read_text(encoding="utf-8")
for line, value in enumerate(text.splitlines(), 1):
for url in re.findall(r'https?://[^\s)>]+', value):
print(f"{line}: {url}")
for target in re.findall(r'\[[^\]]+\]\((?!https?://)([^)#]+)', value):
resolved = (path.parent / target).resolve()
print(f"{line}: internal {target} -> {'OK' if resolved.exists() else 'MISSING'}")
PY
printf '%s\n' '== Changed-file whitespace and conflict markers =='
git diff --check 9adb784902cae19a150146a8fadd6a0491f67814 "$head"
rg -n '^(<<<<<<<|=======|>>>>>>>)' SECURITY.md docs/security/vulnerability-handling.md \
docs/doctoring/vulnerability-disclosure.md CHANGELOG.md test/security-policy-contract.test.ts || trueLength of output: 30999
Finding — medium priority: The regression contract does not protect the no-operational-guarantee boundary.
A future edit could state that private reporting is available or monitored, while this test still passes. Add assertions for these negative boundaries. This change will preserve the central buyer-visible constraint that repository text cannot prove live administrative or operational controls. I found no other actionable issue in the requested scope. The current policy text correctly keeps private reporting conditional, provides a content-free public fallback, limits support to pre-release investigation and remediation, separates source/release/deployment evidence, uses CVSS v4.0 with exploitation-aware prioritization, and avoids bounty, SLA, and 24/7 claims.
|
|
@coderabbitai review Please perform a substantive read-only review of exact current head |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
base='9adb784902cae19a150146a8fadd6a0491f67814'
head='e5db307d54675914640f03e5b92695bc57664d39'
actual="$(git rev-parse HEAD)"
printf 'HEAD=%s\nREQUESTED_HEAD=%s\n' "$actual" "$head"
if [ "$actual" != "$head" ]; then
printf 'ERROR: checked-out revision does not match the requested exact head\n' >&2
exit 2
fi
git cat-file -e "${base}^{commit}"
git cat-file -e "${head}^{commit}"
printf '\n== Exact commit ==\n'
git show -s --format='commit=%H%nparents=%P%nsubject=%s' "$head"
printf '\n== Files changed across the PR range ==\n'
git diff --name-status "$base" "$head"
printf '\n== Relevant file outlines ==\n'
for f in SECURITY.md CHANGELOG.md docs/security/vulnerability-handling.md docs/doctoring/vulnerability-disclosure.md test/security-policy-contract.test.ts; do
if [ -f "$f" ]; then
printf '\n--- %s ---\n' "$f"
if [[ "$f" == *.ts ]]; then
ast-grep outline "$f" --items all || true
else
rg -n '^#{1,6} ' "$f" || true
fi
else
printf 'MISSING: %s\n' "$f"
fi
done
printf '\n== PR diff for review scope ==\n'
git diff --find-renames --unified=20 "$base" "$head" -- \
SECURITY.md \
CHANGELOG.md \
docs/security/vulnerability-handling.md \
docs/doctoring/vulnerability-disclosure.md \
test/security-policy-contract.test.ts
printf '\n== Numbered exact-head content for review scope ==\n'
for f in SECURITY.md CHANGELOG.md docs/security/vulnerability-handling.md docs/doctoring/vulnerability-disclosure.md test/security-policy-contract.test.ts; do
if [ -f "$f" ]; then
printf '\n--- %s ---\n' "$f"
cat -n "$f"
fi
done
printf '\n== Targeted policy-claim search ==\n'
rg -n -i -C 2 \
'(report a vulnerability|private vulnerability reporting|when that control is available|enabled|monitored|staffed|exercised|bug bounty|bounty|compensation|SLA|24.?7|production.ready|supported release|pre.release|content.free|safe harbor|CVSS|known exploited|KEV|incident escalation|CVE|advisory|source identity|release identity|deployment identity|retention)' \
SECURITY.md CHANGELOG.md docs/security/vulnerability-handling.md \
docs/doctoring/vulnerability-disclosure.md test/security-policy-contract.test.ts
printf '\n== Whitespace and conflict-marker checks ==\n'
git diff --check "$base" "$head"
rg -n '^(<<<<<<<|=======|>>>>>>>)' \
SECURITY.md CHANGELOG.md docs/security/vulnerability-handling.md \
docs/doctoring/vulnerability-disclosure.md test/security-policy-contract.test.ts || trueLength of output: 146414
I found no actionable findings in the requested scope. The predecessor regression-contract finding is addressed.
The reviewed documents are consistent on the requested boundaries:
This is review evidence only. It is not approval or merge authority. ✏️ Learnings added
|
|
@coderabbitai review Please perform a substantive read-only review of exact current head |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
base='9adb784902cae19a150146a8fadd6a0491f67814'
head='e5db307d54675914640f03e5b92695bc57664d39'
actual="$(git rev-parse HEAD)"
printf 'HEAD=%s\nREQUESTED_HEAD=%s\n' "$actual" "$head"
if [ "$actual" != "$head" ]; then
printf 'ERROR: checked-out revision does not match the requested exact head\n' >&2
exit 2
fi
git cat-file -e "${base}^{commit}"
git cat-file -e "${head}^{commit}"
printf '\n== Exact commit ==\n'
git show -s --format='commit=%H%nparents=%P%nsubject=%s' "$head"
printf '\n== PR-range changed files ==\n'
git diff --name-status "$base" "$head"
printf '\n== Scoped document structure ==\n'
for f in \
SECURITY.md \
CHANGELOG.md \
docs/security/vulnerability-handling.md \
docs/doctoring/vulnerability-disclosure.md \
test/security-policy-contract.test.ts
do
printf '\n--- %s ---\n' "$f"
test -f "$f" || { printf 'MISSING\n'; continue; }
if [[ "$f" == *.ts ]]; then
ast-grep outline "$f" --items all
else
rg -n '^#{1,6} ' "$f" || true
fi
done
printf '\n== Complete scoped diff ==\n'
git diff --find-renames --unified=30 "$base" "$head" -- \
SECURITY.md \
CHANGELOG.md \
docs/security/vulnerability-handling.md \
docs/doctoring/vulnerability-disclosure.md \
test/security-policy-contract.test.ts
printf '\n== Exact-head scoped contents ==\n'
for f in \
SECURITY.md \
CHANGELOG.md \
docs/security/vulnerability-handling.md \
docs/doctoring/vulnerability-disclosure.md \
test/security-policy-contract.test.ts
do
printf '\n--- %s ---\n' "$f"
cat -n "$f"
done
printf '\n== Claims and regression anchors ==\n'
rg -n -i -C 3 \
'(report a vulnerability|when that control is available|private vulnerability reporting|enabled|monitored|staffed|exercised|notification subscription|response objective|security email|bounty|compensation|SLA|24.?7|production.ready|pre.release|safe harbor|prohibited|destructive|third.party|CVSS|KEV|known exploited|source identity|release identity|deployment identity|incident escalation|CVE|advisory|retention|APA|ISO/IEC|NIST)' \
SECURITY.md CHANGELOG.md docs/security/vulnerability-handling.md \
docs/doctoring/vulnerability-disclosure.md test/security-policy-contract.test.ts
printf '\n== Link targets and diff hygiene ==\n'
python3 - <<'PY'
import re
from pathlib import Path
for name in [
"SECURITY.md",
"docs/security/vulnerability-handling.md",
"docs/doctoring/vulnerability-disclosure.md",
]:
p = Path(name)
print(f"\n{name}")
for n, line in enumerate(p.read_text(encoding="utf-8").splitlines(), 1):
for target in re.findall(r'\[[^\]]+\]\((?!https?://|#)([^)#]+)', line):
print(f"{n}: {target}: {'OK' if (p.parent / target).exists() else 'MISSING'}")
PY
git diff --check "$base" "$head"
rg -n '^(<<<<<<<|=======|>>>>>>>)' \
SECURITY.md CHANGELOG.md docs/security/vulnerability-handling.md \
docs/doctoring/vulnerability-disclosure.md test/security-policy-contract.test.ts || trueLength of output: 172329 You are interacting with an AI system. |
|
@coderabbitai review Please perform a substantive review of the exact current head |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
base='9adb784902cae19a150146a8fadd6a0491f67814'
head='e5db307d54675914640f03e5b92695bc57664d39'
actual="$(git rev-parse HEAD)"
printf 'HEAD=%s\nREQUESTED_HEAD=%s\n' "$actual" "$head"
if [ "$actual" != "$head" ]; then
printf 'ERROR: checked-out revision does not match requested exact head\n' >&2
exit 2
fi
git cat-file -e "${base}^{commit}"
git cat-file -e "${head}^{commit}"
printf '\n== Exact commit ==\n'
git show -s --format='commit=%H%nparents=%P%nsubject=%s' "$head"
printf '\n== PR-range changed files ==\n'
git diff --name-status "$base" "$head"
printf '\n== Document structure and test outline ==\n'
for f in \
SECURITY.md \
CHANGELOG.md \
docs/security/vulnerability-handling.md \
docs/doctoring/vulnerability-disclosure.md \
test/security-policy-contract.test.ts
do
printf '\n--- %s ---\n' "$f"
test -f "$f" || { printf 'MISSING\n'; continue; }
if [[ "$f" == *.ts ]]; then
ast-grep outline "$f" --items all
else
rg -n '^#{1,6} ' "$f" || true
fi
done
printf '\n== Exact-head review-scope contents ==\n'
for f in \
SECURITY.md \
CHANGELOG.md \
docs/security/vulnerability-handling.md \
docs/doctoring/vulnerability-disclosure.md \
test/security-policy-contract.test.ts
do
printf '\n--- %s ---\n' "$f"
cat -n "$f"
done
printf '\n== Claims and regression anchors ==\n'
rg -n -i -C 3 \
'(report a vulnerability|when that control is available|private vulnerability reporting|enabled|monitored|staffed|exercised|notification subscription|response objective|security email|bounty|compensation|SLA|24.?7|production.ready|pre.release|safe harbor|prohibited|destructive|third.party|CVSS|KEV|known exploited|source identity|release identity|deployment identity|incident escalation|CVE|advisory|retention|APA|ISO/IEC|NIST)' \
SECURITY.md CHANGELOG.md docs/security/vulnerability-handling.md \
docs/doctoring/vulnerability-disclosure.md test/security-policy-contract.test.ts
printf '\n== Internal documentation links ==\n'
python3 - <<'PY'
import re
from pathlib import Path
for filename in (
"SECURITY.md",
"docs/security/vulnerability-handling.md",
"docs/doctoring/vulnerability-disclosure.md",
):
path = Path(filename)
print(f"\n{filename}")
for line_number, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
for target in re.findall(r'\[[^\]]+\]\((?!https?://|#)([^)#]+)', line):
print(f"{line_number}: {target}: {'OK' if (path.parent / target).exists() else 'MISSING'}")
PY
printf '\n== Diff hygiene ==\n'
git diff --check "$base" "$head"
rg -n '^(<<<<<<<|=======|>>>>>>>)' \
SECURITY.md CHANGELOG.md docs/security/vulnerability-handling.md \
docs/doctoring/vulnerability-disclosure.md test/security-policy-contract.test.ts || trueLength of output: 118394 🤖 web_search executed: `Use primary sources only. Verify the following claims for a documentation review:
Length of output: 12197 🤖 web_search executed:
Length of output: 17412
I found no actionable findings in the requested scope. The regression contract now protects the operational boundary.
The reviewed documents are consistent:
The scoped inspection found no broken internal links, conflict markers, or whitespace errors. I did not execute tests. This review is current-head evidence only. It is not approval, merge authority, release authority, or deployment authority. It does not treat queued, failed, stale-head, or status-only evidence as success. ✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@docs/security/vulnerability-handling.md`:
- Line 147: Expand the evidence-retention guidance around “Retain only the data
necessary” to define bounded maximum retention periods for each evidence class,
the owner responsible for expiry review, role-based access, legal-hold
exceptions, and secure deletion or redaction evidence. Add contract tests that
lock these lifecycle requirements and explicitly cover reporter contact data,
PII, and secrets.
- Around line 43-48: 문서 절차에 SECURITY.md의 공개 fallback lifecycle을 추가하세요. Private
security contact requested 이슈의 담당자 지정, private channel 안내, 취약점 세부정보를 공개 이슈에 요청하지
않는 원칙, private case로 전환하는 단계를 명시하고, 6단계의 “public service objective”를
SECURITY.md의 published service objective와 동일한 용어로 변경하세요.
In `@test/security-policy-contract.test.ts`:
- Around line 89-90: Update the changelog assertion in the security policy
contract test to extract only the section beginning at the “## Unreleased”
heading and ending before the next “##” heading, then check that section for
“coordinated vulnerability disclosure”. Make the test fail when the “##
Unreleased” heading is absent.
🪄 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: dcd0e23b-b32d-482c-8b63-278c1171e3e7
📒 Files selected for processing (5)
CHANGELOG.mdSECURITY.mddocs/doctoring/vulnerability-disclosure.mddocs/security/vulnerability-handling.mdtest/security-policy-contract.test.ts
Summary
Establishes Noema's coordinated vulnerability disclosure policy and evidence-preserving handling lifecycle, and adds a test-first, read-only operational probe plus operator runbook for GitHub private vulnerability reporting without claiming the administrator control is enabled or exercised.
Exact source
mainat9adb784902cae19a150146a8fadd6a0491f67814.7bb27c518fb94e4ac5abd9f8f26479f964db6995.mainPR; no stack predecessor.Implemented boundary
SECURITY.mddefines the pre-release support boundary, private-reporting-first intake, content-free public fallback, bounded scope/safe harbor, non-contractual response objectives, CVSS v4.0 plus exploitation-aware prioritization, coordinated disclosure, and no invented bounty/support commitment;docs/security/vulnerability-handling.mddefines role separation, case states, private intake, exact source/release/deployment identity, bounded reproduction, incident escalation, test-first remediation, independent review, advisory/CVE/release separation, recovery, lessons learned, retention maxima, scoped legal hold, access roles, and deletion/redaction evidence;docs/doctoring/vulnerability-disclosure.mdrecords the standards/research rationale with APA 7 references and distinguishes Noema-specific retention decisions from external standards requirements;test/security-policy-contract.test.tsmakes the fallback lifecycle, retention controls, doctoring, and## Unreleasedchangelog contract executable;scripts/lib/private-vulnerability-reporting-audit.mjsdeterministically accepts only an explicit GitHubenabled: truestatus and fails closed on disabled or malformed evidence;scripts/private-vulnerability-reporting-audit.mjsperforms only a boundedGETto GitHub's private-vulnerability-reporting status endpoint, refuses cross-organization repository identifiers, applies a 20-second timeout and 16 KiB streamed response ceiling, emits machine-readableartifacts/security/private-vulnerability-reporting-audit.json, and returns failure unless the status is explicitly enabled;test/private-vulnerability-reporting-audit.test.tspins endpoint, method, version header, output/fail-closed semantics, evidence limitations, and the operator-runbook contract;test/private-vulnerability-reporting-adapter.test.tsproves the adapter streams instead of using an unbounded complete-body buffering path and rejects both oversized declared and oversized streamed responses;docs/security/private-vulnerability-reporting-audit.mdgives the exact collection command, evidence path, fail-closed interpretation, retention boundary, content-free fallback behavior, and the live operational acceptance checklist owned by security: enable and evidence private vulnerability reporting #73.The adapter's first implementation bounded bytes only after
response.text()had already buffered the complete remote body. That violated the intended untrusted-input boundary. A RED streamed-adapter contract was added at698db41561f310390d515e45e3304cc4a6f75408; the subsequent implementation introduced incremental byte counting and early cancellation. A later RED runbook contract was satisfied by the dedicated operational-evidence runbook at the current head.Current exact-head evidence
For unchanged exact head
7bb27c518fb94e4ac5abd9f8f26479f964db6995:cirun31332529454: terminal failure only at the inherited repository-widenpm audit --audit-level=highboundary for protected-mainnanoid <3.3.17/ GHSA-2v37-7h3g-55p8. Before that boundary, typecheck succeeded and 64 test files / 657 tests passed, including all private-reporting evaluator, streamed-adapter, and runbook-contract tests, with configured owned statement/branch/function/line coverage all 100%. The workflow checked GitHub's synthetic integration commit538e7d4621f57556c26a40d1a88da8dd4a702fca, so those results are integration evidence rather than immutable-head checkout proof;reviewer-cirun31332529436: terminal success;Security Scanrun31332529441: terminal success;CodeRabbitcommit status: success, retained only as commit-status evidence;COMMENTEDevidence; there is no qualifying independent non-authorAPPROVEDreview.The inherited dependency root fix remains isolated in #75/#76. Duplicating its lockfile remediation here or weakening
npm auditis rejected.Operational gap intentionally remains open
The repository now detects and documents how to evidence the GitHub private-vulnerability-reporting setting without write authority, but repository code does not prove that the live setting is enabled, that the external reporter UI is visible, that multiple authorized maintainers/security owners receive and can access reports, that notifications route correctly, or that a benign end-to-end private-report exercise has succeeded. Canonical issue #73 owns those administrator/operational acceptance items and remains open.
A passing setting probe is not notification-routing, staffing, case-handling, review, release, deployment, or acquisition evidence by itself.
Authority and safety boundaries
contents:write, protection bypass, audit waiver, or synthetic approval;Merge boundary
Do not merge until the unchanged exact head satisfies the actual required CI/security/coverage/provenance gates, all valid current findings remain addressed, enforceable
maingovernance under #27 is present, and qualifying independent approval is satisfied where required. #76 must first remove the inherited dependency-audit failure under its own gates. No version bump or release is warranted for this unintegrated policy/control slice.Related: #73, #27, #29, #40, #75, #76, #77, #78