fix(compose): rebuild loopback publishing on current main - #138
Conversation
📝 WalkthroughWalkthrough독립형 Compose 프로필의 PostgreSQL 및 component 포트를 IPv4 loopback으로 제한했습니다. 레거시 health port 설정을 제거했습니다. Compose 정규화 결과를 검사하는 네트워크 경계 테스트와 운영 문서를 추가했습니다. ChangesCompose loopback 포트 경계
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@tests/test_compose_network_boundary.py`:
- Around line 20-41: Require Docker Engine 28.0.0 or newer across the Compose
security checks: update _compose_model in tests/test_compose_network_boundary.py
to query and validate the daemon Server version, failing below 28.0.0; update
the local-only comment in docker-compose.yml at lines 17-19 to state the
supported runtime requirement; and update
docs/doctoring/compose-loopback-publishing.md at line 11 to document the minimum
version and the L2 exposure risk on older engines.
🪄 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: 1614785d-ab15-4e01-8da9-841930331ecc
📒 Files selected for processing (4)
CHANGELOG.mddocker-compose.ymldocs/doctoring/compose-loopback-publishing.mdtests/test_compose_network_boundary.py
| def _compose_model() -> dict[str, Any]: | ||
| """Return Docker Compose's normalized JSON model for the standalone stack.""" | ||
| docker = shutil.which("docker") | ||
| assert docker is not None, "Docker CLI is required to validate Compose security" | ||
| result = subprocess.run( | ||
| [ | ||
| docker, | ||
| "compose", | ||
| "-f", | ||
| str(_COMPOSE_PATH), | ||
| "config", | ||
| "--format", | ||
| "json", | ||
| ], | ||
| cwd=_ROOT, | ||
| check=True, | ||
| capture_output=True, | ||
| text=True, | ||
| ) | ||
| model = json.loads(result.stdout) | ||
| assert isinstance(model, dict) | ||
| return model |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
sed -n '1,120p' tests/test_compose_network_boundary.py
printf '\n--- docker-compose.yml ---\n'
sed -n '1,80p' docker-compose.yml
printf '\n--- documentation ---\n'
sed -n '1,80p' docs/doctoring/compose-loopback-publishing.md
printf '\n--- repository references ---\n'
rg -n --hidden -S '28\.0\.0|Server Version|docker version|compose_network|loopback|local-only|5432:5432|8080:8080' \
-g '!node_modules' -g '!dist' -g '!build' .Repository: ContextualWisdomLab/pg-llm-batch
Length of output: 11486
🌐 Web query:
Docker Engine port publishing localhost L2 access 28.0.0 release notes
💡 Result:
In Docker Engine 28.0.0, a significant security improvement addresses how ports bound to the loopback interface (localhost) are accessed [1][2]. Historically, in versions older than 28.0.0, ports published to localhost (e.g., -p 127.0.0.1:8080:80) could still be accessed by other hosts on the same Layer 2 (L2) network segment due to the way Docker managed iptables rules [1][3]. This meant that traffic destined for 127.0.0.1 could bypass expected host-level restrictions and be reached by remote devices on the local area network [3][2]. Docker Engine 28.0.0 resolves this by hardening container networking, ensuring that ports explicitly bound to the localhost interface are not accessible from external hosts on the LAN [1][2]. Additionally, Docker 28.0.0 introduces a default "secure by default" posture where unpublished container ports are no longer accessible from remote LAN hosts, even if the host's filter-FORWARD policy is set to ACCEPT [2][4]. For further details, refer to the official Docker Engine 28 release notes and the associated documentation on port publishing [5][1].
Citations:
- 1: https://docs.docker.com/engine/network/port-publishing/
- 2: https://www.docker.com/blog/docker-engine-28-hardening-container-networking-by-default/
- 3: Publishing ports explicitly to private networks should not be accessible from LAN hosts moby/moby#45610
- 4: Remove dependency on the filter-FORWARD policy moby/moby#48724
- 5: https://docs.docker.com/engine/release-notes/28/
Docker Engine 28.0.0 이상을 요구하고 강제하세요.
Docker Engine 28.0.0 미만에서는 127.0.0.1에 게시한 포트가 같은 L2 네트워크의 원격 호스트에서 접근될 수 있습니다.
- 테스트에서 Docker daemon의 Server 버전을 검사하고, 28.0.0 미만이면 실패시키세요.
docker-compose.yml의local-only주석을 지원 런타임 조건에 맞게 수정하세요.- 문서에 Docker Engine 28.0.0 이상 요구사항과 이전 버전의 L2 노출 위험을 명시하세요.
🧰 Tools
🪛 ast-grep (0.45.1)
[error] 23-37: Command coming from incoming request
Context: subprocess.run(
[
docker,
"compose",
"-f",
str(_COMPOSE_PATH),
"config",
"--format",
"json",
],
cwd=_ROOT,
check=True,
capture_output=True,
text=True,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(subprocess-from-request)
📍 Affects 3 files
tests/test_compose_network_boundary.py#L20-L41(this comment)docker-compose.yml#L17-L19docs/doctoring/compose-loopback-publishing.md#L11-L11
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/test_compose_network_boundary.py` around lines 20 - 41, Require Docker
Engine 28.0.0 or newer across the Compose security checks: update _compose_model
in tests/test_compose_network_boundary.py to query and validate the daemon
Server version, failing below 28.0.0; update the local-only comment in
docker-compose.yml at lines 17-19 to state the supported runtime requirement;
and update docs/doctoring/compose-loopback-publishing.md at line 11 to document
the minimum version and the L2 exposure risk on older engines.
|
138 |
Purpose
Rebuild the standalone Compose loopback-publishing security boundary directly on the current protected-main line instead of carrying the stale ancestry of #91.
TDD / replacement boundary
This replacement starts from protected
mainat20283526e3b23f9ceb144a90467763e1f4910321. The original #91 feature owns five paths; current protected-main changes since #91's old base do not touchdocker-compose.yml,docs/doctoring/compose-loopback-publishing.md, ortests/test_compose_network_boundary.py. README/CHANGELOG require deliberate composition rather than conflict-side selection.Current RED head
9abb15a2ffa6e9464cd318809ab8b6dbf6e910f8adds the exact normalized-Compose security regression first. It must fail while protected main still publishes PostgreSQL and health on all interfaces and still advertises the obsoletePG_LLM_BATCH_HEALTH_PORTenvironment knob. Production/docs changes follow only after that RED is observed.No evidence from #91 transfers to this branch; all required checks/reviews must be reacquired on this replacement head.
Intended bounded behavior
127.0.0.1:5432:5432only.127.0.0.1:8080:8080only.PG_LLM_BATCH_HEALTH_PORTCompose environment override.pgdatavolume structure.Keep Draft until RED -> GREEN, focused/full validation, exact-current-head required workflows, and current review-thread policy are satisfied.
Summary by CodeRabbit
보안 개선
문서
테스트