Skip to content

fix(container): APP_HOST defaults to 127.0.0.1 (HCG tier-2 E1 prereq)#132

Merged
hyperpolymath merged 2 commits into
mainfrom
fix/boj-stapeln-loopback
May 20, 2026
Merged

fix(container): APP_HOST defaults to 127.0.0.1 (HCG tier-2 E1 prereq)#132
hyperpolymath merged 2 commits into
mainfrom
fix/boj-stapeln-loopback

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Summary

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. The scope expanded during implementation from one site (the audit named stapeln.toml) to three sites — entrypoint.sh and compose.prod.yaml had the same [::] default that the audit missed. All three sites feed into the same Zig-adapter --host flag, 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

File Change
stapeln.toml [targets.production] APP_HOST = "[::]"APP_HOST = "127.0.0.1" + comment block.
container/entrypoint.sh line 40 (log) + line 140 (exec invocation) ${APP_HOST:-[::]}${APP_HOST:-127.0.0.1} + comment at exec line.
container/compose.prod.yaml services.boj-rest.environment APP_HOST: "[::]"APP_HOST: "127.0.0.1" + comment block.
CHANGELOG.md New ### Changed entry under [Unreleased].

Override path for legacy/standalone use

Deployments without HCG in front: set APP_HOST=0.0.0.0 (IPv4 all-interfaces) or APP_HOST=:: (IPv6 all-interfaces) in your deployment config. The in-repo defaults remain loopback.

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 by grep -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.
  • Unifying APP_HOST (Zig adapter) and BOJ_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.yaml as-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 explicit APP_HOST=0.0.0.0 override).

Test plan

  • stapeln.toml parses as valid TOML (syntax preserved).
  • container/entrypoint.sh runs through sh -n without syntax error (no syntax change, just literal substitution).
  • container/compose.prod.yaml parses as valid YAML.
  • CI green — governance / hypatia / a2ml / k9 / dogfooding all pass.
  • Owner: confirm no live deployment depends on [::] default; flip from DRAFT to ready.
  • Post-merge manual: a stapeln-built production container, with no env override, refuses connections from non-loopback peers.

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.0 explicitly. Reasonable default for the Phase E posture; documented override path.

🤖 Generated with Claude Code

@hyperpolymath hyperpolymath reopened this May 20, 2026
@hyperpolymath hyperpolymath marked this pull request as ready for review May 20, 2026 10:21
@hyperpolymath
Copy link
Copy Markdown
Owner Author

CI auto-trigger anomaly — manual dispatch worked

PR-triggered workflows did not fire on this branch (no pull_request events for either the initial push bda043dc or the no-op empty commit e44b2799). Close+reopen and ready-flip also failed to re-trigger. Other PRs opened in this session (#130, #131) and other sessions (#129) got their checks normally.

Hypothesis: estate-wide CI concurrency-pool saturation from the active sweep122 campaign ([memory: project_ci_concurrency_pool_estate]) — Terminal-7 launched at 09:33Z (PID 244005) is opening dup PRs across ~297 repos. The workflow_dispatch code path still works.

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

  • ✓ Security policy checks
  • ✓ Well-Known (RFC 9116 + RSR)
  • ✓ Guix primary / Nix fallback policy
  • ✓ Code quality + docs
  • ✓ Language / package anti-pattern policy
  • ✓ Workflow security linter

Other workflows (Dogfood Gate, CodeQL, Secret Scanner) don't support workflow_dispatch and so can't be manually triggered. Suggest the owner either (a) waits for the concurrency pool to free up and re-runs via the Actions tab, or (b) merges the v2 branch superseded earlier if checks resume; my PR's content is safe to land without CodeQL+Secret-Scanner+Dogfood since the diff is configuration-only (TOML + shell ${VAR:-default} substitution + YAML).

Leaving the PR DRAFT until checks land.

🤖 Generated with Claude Code

hyperpolymath and others added 2 commits May 20, 2026 13:23
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>
@hyperpolymath hyperpolymath force-pushed the fix/boj-stapeln-loopback branch from e44b279 to 5830a46 Compare May 20, 2026 12:23
@hyperpolymath hyperpolymath merged commit 5699de0 into main May 20, 2026
16 checks passed
@hyperpolymath hyperpolymath deleted the fix/boj-stapeln-loopback branch May 20, 2026 12:35
hyperpolymath added a commit that referenced this pull request May 20, 2026
…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>
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 30 issues detected

Severity Count
🔴 Critical 18
🟠 High 5
🟡 Medium 7

⚠️ Action Required: Critical security issues found!

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

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.

1 participant