fix(container): APP_HOST defaults to 127.0.0.1 (HCG tier-2 E1 prereq)#132
Conversation
CI auto-trigger anomaly — manual dispatch workedPR-triggered workflows did not fire on this branch (no Hypothesis: estate-wide CI concurrency-pool saturation from the active sweep122 campaign ([memory: Manual dispatch result for Governance (the most relevant check given the file types in this PR — TOML + shell + YAML): all 6 jobs green at https://github.com/hyperpolymath/boj-server/actions/runs/26156354986
Other workflows (Dogfood Gate, CodeQL, Secret Scanner) don't support Leaving the PR DRAFT until checks land. 🤖 Generated with Claude Code |
Tightens three sites that feed the Zig adapter binary's `--host` flag in production deployments, materialising the ADR-0004 §1 invariant that BoJ's back-side bind is not externally routable when fronted by http-capability-gateway (HCG tier-2). This is action item #7 from the Phase E consumer-side audit on hyperpolymath/standards#100 — companion to actions #6 (boj-server#130, Cowboy bind in the Elixir path) and #8 (boj-server#131, k8s Service ClusterIP). Together the three layers give defence in depth: Elixir Cowboy binds loopback, Zig adapter binds loopback, k8s Service is internal-only. Changes: - `stapeln.toml` [targets.production]: `APP_HOST = "[::]"` -> `APP_HOST = "127.0.0.1"`. Adds a comment block explaining the Phase E posture and the override path for legacy deployments. - `container/entrypoint.sh` lines 40 + 140: `${APP_HOST:-[::]}` -> `${APP_HOST:-127.0.0.1}`. Adds a comment at the exec line pointing to ADR-0004 + the runbook. - `container/compose.prod.yaml` services.boj-rest.environment: `APP_HOST: "[::]"` -> `APP_HOST: "127.0.0.1"`. Adds an inline comment block. Audit-residue follow-ups (deliberately NOT in this PR): - `container/Containerfile` line 125: `ENV PHX_HOST=0.0.0.0` is vestigial — nothing in the codebase reads PHX_HOST (verified via grep). Leave alone or remove in a hygiene PR; not load-bearing. - Unifying APP_HOST (Zig adapter) and BOJ_BIND_IP (Elixir Cowboy) into one envelope is broader scope; file as a separate issue if the divergence proves annoying in operation. Override path for legacy/standalone deployments without HCG in front: set APP_HOST=0.0.0.0 (IPv4 all-interfaces) or APP_HOST=:: (IPv6 all-interfaces) in the deployment config — the in-repo defaults remain loopback. Refs hyperpolymath/standards#100 Refs hyperpolymath/standards#91 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
e44b279 to
5830a46
Compare
…ds#100/#91) (#138) ## Summary Adds a second 2026-05-20 entry to `.machine_readable/6a2/STATE.a2ml` `[session-history]` documenting the afternoon HCG Phase E first-session output. The morning Tier C entry (already in main) stays in place; this new entry sits **above** it per the newest-first convention. `Refs hyperpolymath/standards#100` (Phase E), `Refs hyperpolymath/standards#91` (HCG tier-2 channel parent). **NOT Closes**. ## What's in A single new TOML entry in `[session-history] entries = [ ... ]` summarising the afternoon's deliverables: - PR `#128` (MERGED) — `docs/integration/hcg-tier2-rollout-runbook.md` (E5 rollout-and-rollback runbook, 308 lines, `!OWNER:` markers in §1.3 + §4) - PR `#130` (MERGED) — Cowboy bind `127.0.0.1` default + `BOJ_BIND_IP` env override (audit #6) - PR `#131` (MERGED) — k8s Service `LoadBalancer → ClusterIP` (audit #8) - PR `#132` (MERGED) — container `APP_HOST` defaults across `stapeln.toml` + `entrypoint.sh` + `compose.prod.yaml` (audit #7) - Issue `#135` (filed) — k8s NetworkPolicy follow-up (Low priority, Phase E acceptance non-critical) - Defence in depth: 3 independent loopback layers (Elixir Cowboy + Zig adapter + k8s Service) - Phase C §3 invariant 3 correction: confirmed via `git log` that the deny clause landed in `boj-server#106 (40e46f6)`; the channel-status comment claiming it was owner-gated was stale. The entry also records the **Phase E gating posture**: E1/E2/E3/E4 wiring + Trustfile `PENDING → DEPLOYED` flip are all explicitly gated on Phase D-3 (regression alert armed) + D-4 (real baseline numbers populated), per the runbook §1.1. The afternoon session shipped only the Phase-D-independent artefacts. ## Why a separate PR (not amended into another) All four code PRs (#128/#130/#131/#132) are already merged. The STATE.a2ml entry parallels the morning Tier C entry (already in main from the morning session), and the convention is per-session per-entry. Keeping this as its own doc PR is the cleanest record. ## Verification - TOML syntax: valid (single new `{ date = "...", description = "..." }` entry prepended). - Linting: `validate-a2ml` action will run on PR. ## Risk **Negligible.** Doc-only; no code or workflow changes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 30 issues detected
View findings[
{
"reason": "Stale AI session file -- delete",
"type": "stale",
"file": "GEMINI.md",
"action": "delete",
"rule_module": "root_hygiene",
"severity": "medium"
},
{
"reason": "Issue in quality.yml",
"type": "missing_workflow",
"file": "quality.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Issue in security-policy.yml",
"type": "missing_workflow",
"file": "security-policy.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/sanctify-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/academic-workflow-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/fireflag-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/ephapax-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/bofig-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/boj-server/boj-server/cartridges/hesiod-mcp/adapter/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
Summary
Tightens three sites that feed the Zig adapter binary's
--hostflag in production deployments, materialising the ADR-0004 §1 invariant that BoJ's back-side bind is not externally routable when fronted byhttp-capability-gateway(HCG tier-2).This is action item #7 from the Phase E consumer-side audit. The scope expanded during implementation from one site (the audit named
stapeln.toml) to three sites —entrypoint.shandcompose.prod.yamlhad the same[::]default that the audit missed. All three sites feed into the same Zig-adapter--hostflag, so they need to flip together for the change to actually take effect at runtime.Companion PR to #130 (Cowboy bind tightening in the Elixir path) and #131 (k8s Service ClusterIP). Together the three give defence in depth: Elixir Cowboy binds loopback AND Zig adapter binds loopback AND k8s Service is internal-only.
Refs hyperpolymath/standards#100(NOT Closes — joint-close is owner-only).Refs hyperpolymath/standards#91.What's in
stapeln.toml[targets.production]APP_HOST = "[::]"→APP_HOST = "127.0.0.1"+ comment block.container/entrypoint.shline 40 (log) + line 140 (execinvocation)${APP_HOST:-[::]}→${APP_HOST:-127.0.0.1}+ comment at exec line.container/compose.prod.yamlservices.boj-rest.environmentAPP_HOST: "[::]"→APP_HOST: "127.0.0.1"+ comment block.CHANGELOG.md### Changedentry under[Unreleased].Override path for legacy/standalone use
Deployments without HCG in front: set
APP_HOST=0.0.0.0(IPv4 all-interfaces) orAPP_HOST=::(IPv6 all-interfaces) in your deployment config. The in-repo defaults remain loopback.Audit-residue follow-ups deliberately NOT in this PR
container/Containerfileline 125:ENV PHX_HOST=0.0.0.0is vestigial. Nothing in the codebase readsPHX_HOST(verified bygrep -rn "PHX_HOST\|phx_host" --include="*.ex" ...returning empty). Leftover from a former Phoenix incarnation. Safe to leave alone; can be removed in a hygiene PR if desired.APP_HOST(Zig adapter) andBOJ_BIND_IP(Elixir Cowboy from fix(boj): bind Cowboy to 127.0.0.1 by default (HCG tier-2 E1 prereq) #130) into one envelope is broader scope. The divergence exists because they feed different binaries built by different toolchains. If it proves annoying in operation, file a separate issue.Why DRAFT
Same reason as #131 — this is a behaviour change for anyone running the stapeln-built production container or
compose.prod.yamlas-is and relying on the default[::]for external access. Owner gates merge on confirming no such reliance, or on coordinating with anyone who needs the migration path (HCG-in-front, or explicitAPP_HOST=0.0.0.0override).Test plan
stapeln.tomlparses as valid TOML (syntax preserved).container/entrypoint.shruns throughsh -nwithout syntax error (no syntax change, just literal substitution).container/compose.prod.yamlparses as valid YAML.[::]default; flip from DRAFT to ready.Risk
Low for the codebase, medium for ops. No Elixir / Zig / Idris2 / cartridge logic touched; CI should not show any regressions. Ops risk: anyone whose runbook assumes the container exposes BoJ on all interfaces by default will need to set
APP_HOST=0.0.0.0explicitly. Reasonable default for the Phase E posture; documented override path.🤖 Generated with Claude Code