Expose a runnable backend without giving the ingress layer secrets
Some checks failed
verify / verify (push) Has been cancelled

The backend can now be inspected through a loopback-only gateway while the database-aware API remains on the internal data network. A governed synthetic demo proves readiness, pgvector retrieval, reranking, and citation output through real HTTP without invoking cloud models.

Constraint: The previously exposed Bailian key is compromised and cannot be used for live validation

Constraint: The API must be locally reachable while retaining no internet egress

Rejected: Attach the API directly to the ingress network | a real socket test proved that configuration still had egress

Rejected: Publish a port from the internal-only network | Docker Desktop did not expose the host port

Confidence: high

Scope-risk: moderate

Reversibility: clean

Directive: Keep model and database credentials out of the gateway; do not relax the fixed demo identity/profile filters

Tested: make verify; 63 pytest tests; strict mypy; Ruff; Secret scan; Compose config; three backend image builds; API/DB/gateway healthy; migration exit 0; Swagger browser check; live/ready/meta/status/search HTTP; 20/20/20 index; API egress ENETUNREACH; empty gateway mounts and business environment

Not-tested: Live Bailian calls require a newly rotated key; full generated-answer flow and React UI are not implemented
This commit is contained in:
2026-07-12 16:37:02 +08:00
parent e89cca2b55
commit cfd6d4cbad
16 changed files with 1207 additions and 37 deletions

View File

@@ -17,6 +17,8 @@ from app.persistence.job_queue_sql import ( # noqa: E402
)
COMPOSE = (ROOT / "compose.yaml").read_text(encoding="utf-8")
DOCKERFILE = (BACKEND / "Dockerfile").read_text(encoding="utf-8")
DEMO_API = (BACKEND / "app/api/v1/demo.py").read_text(encoding="utf-8")
BOOTSTRAP = (ROOT / "ops/postgres/init/10-bootstrap-rag.sh").read_text(encoding="utf-8")
MIGRATION = (BACKEND / "migrations/versions/0001_initial_schema.py").read_text(encoding="utf-8")
@@ -31,6 +33,8 @@ def _service_block(name: str) -> str:
def test_compose_isolates_database_credentials_and_networks() -> None:
db = _service_block("db")
migrate = _service_block("migrate")
api = _service_block("api")
gateway = _service_block("gateway")
provider_smoke = _service_block("provider-smoke")
seed_demo = _service_block("seed-demo")
seed_demo_offline = _service_block("seed-demo-offline")
@@ -43,6 +47,27 @@ def test_compose_isolates_database_credentials_and_networks() -> None:
assert "postgres_bootstrap_password" not in migrate
assert "postgres_app_password" not in migrate
assert "postgres_app_password" in api
assert "postgres_bootstrap_password" not in api
assert "postgres_migrator_password" not in api
assert "bailian_api_key" not in api
assert '"127.0.0.1:8000:8000"' not in api
assert " - data" in api
assert " - edge" not in api
assert " - egress" not in api
assert "read_only: true" in api
assert "no-new-privileges:true" in api
assert "cap_drop:" in api and " - ALL" in api
assert '"127.0.0.1:8000:8000"' in gateway
assert " - edge" in gateway
assert " - data" in gateway
assert "secrets:" not in gateway
assert "POSTGRES_" not in gateway
assert "BAILIAN_" not in gateway
assert "read_only: true" in gateway
assert "no-new-privileges:true" in gateway
assert "bailian_api_key" in provider_smoke
assert "postgres_" not in provider_smoke
@@ -61,6 +86,34 @@ def test_compose_isolates_database_credentials_and_networks() -> None:
assert re.search(r"(?m)^ edge:$", COMPOSE)
assert re.search(r"(?m)^ egress:$", COMPOSE)
assert "USER 10001:10001" in DOCKERFILE
assert 'CMD ["uvicorn", "app.main:app"' in DOCKERFILE
def test_demo_queries_pin_governed_offline_identity() -> None:
normalized = " ".join(DEMO_API.split())
for required_filter in (
"chunk.knowledge_base_id = %s",
"chunk.access_scope_id = %s",
"chunk.metadata ->> 'source_type' = 'synthetic'",
"chunk.searchable IS TRUE",
"chunk.index_status = 'READY'",
"chunk.approval_status = 'CLOUD_APPROVED'",
"document.active_version_id = chunk.document_version_id",
"version.review_state = 'CLOUD_APPROVED'",
"version.outbound_manifest_sha256 = chunk.outbound_manifest_sha256",
"version.embedding_profile_hash = chunk.embedding_profile_hash",
"chunk.embedding_model = %s",
"chunk.embedding_profile_hash = %s",
):
assert required_filter in normalized
assert "KNOWLEDGE_BASE_ID" in DEMO_API
assert "ACCESS_SCOPE_ID" in DEMO_API
assert "DEMO_FAKE_EMBEDDING_MODEL" in DEMO_API
assert "offline_embedding_profile_hash" in DEMO_API
def test_database_health_requires_tcp_and_atomic_bootstrap_sentinel() -> None:
db = _service_block("db")