KB-6B9F rev 2

dot-iu-cutter v0.4 — Connection Env Keys Command-Review Package r2 (FR-1 resolved; command-review only; not executed)

16 min read Revision 2
dot-iu-cutterdieu44v0.4db-adaptercommand-reviewenv-keysfr-1-resolvednot-executed

dot-iu-cutter v0.4 — Connection Env Keys Command-Review Package

document_path: knowledge/dev/laws/dieu44-trien-khai/v0.4-db-adapter-execution/dot-iu-cutter-v0.4-connection-env-keys-command-review-package-2026-05-17.md
revision: r2
date: 2026-05-17
author: Agent (Claude Code CLI, Opus 4.7 1M)
verifier: GPT (review pending — r2 routes the FR-1 resolution + revised command-review in)
phase: v0.4 — CONNECTION ENV KEYS COMMAND-REVIEW (command-review only)
opened_by: GPT command-review r1 review = substance PASS, execution NOT
  authorized, FR-1 must be resolved before any .env write
  + explicit User "v0.4 connection env keys FR-1 resolution + r2" prompt.
status: command_review_only_pending_gpt_review — NOTHING EXECUTED
delta_from_r1: ONLY DOT_CUTTER_DB_SSLMODE require → disable (FR-1 resolved
  via read-only prod SSL inspection §3a). Command sequence C-01..C-08,
  safety gates G-1..G-8, rollback plan, non-scope = UNCHANGED from r1.

⛔ COMMAND-REVIEW ONLY. NOT executed. No .env edit, no secret value read/printed, no runtime connection, no code change, no dry-run, no CUT/VERIFY, no deploy, no service restart, no role/GRANT change, no secret rotation. Read-only docker topology + read-only PostgreSQL SSL inspection were performed (authorized); they changed nothing.


§1 — Objective

Add exactly four non-secret, shared connection component keys to the approved substrate /opt/incomex/docker/.env so a FUTURE authorized code cycle can build a connection without hardcoding host/port/db/sslmode and without any DSN-with-password (per design docs 2/3 + GPT DA-1):

DOT_CUTTER_DB_HOST   DOT_CUTTER_DB_PORT   DOT_CUTTER_DB_NAME   DOT_CUTTER_DB_SSLMODE

No password material is added, read, or touched. The 4 LIVE credential keys are NOT modified.

§2 — Current .env Key Inventory (read-only; NO values printed)

Verified by read-only inspection on VPS 38.242.240.89 (key NAMES only, via grep -oE '^DOT_CUTTER[A-Za-z0-9_]*=' … | tr -d '=' — values never read):

env_file: /opt/incomex/docker/.env
permissions: 600 root:root   (CONFIRMED — satisfies gate G-1)
credential_keys_present (names only, values NEVER read/printed):
  - DOT_CUTTER_EXEC_DB_USER       PRESENT
  - DOT_CUTTER_EXEC_DB_PASSWORD   PRESENT
  - DOT_CUTTER_VERIFY_DB_USER     PRESENT
  - DOT_CUTTER_VERIFY_DB_PASSWORD PRESENT
  → exactly the 4 GPT-accepted live credential keys (credential-execution
    report §6 / GPT credential review §4). Satisfies gate G-2.
target_connection_keys (the 4 to be added):
  grep -cE '^DOT_CUTTER_DB_(HOST|PORT|NAME|SSLMODE)=' = 0  → ALL ABSENT
  → no pre-existing / duplicate / conflicting DOT_CUTTER_DB_* keys.
    Satisfies gate G-4.

§3 — Host Discovery (read-only topology; NOT guessed)

Evidence from docker ps, docker network ls, docker inspect postgres, and read-only docker-compose.yml service/network grep:

compose_dir: /opt/incomex/docker  (docker-compose.yml; .env is its substrate)
compose_network: docker_incomex   (bridge, local) — the single app network
postgres_container:
  container_name: postgres
  image: postgres:16
  network: docker_incomex
  network_aliases: [postgres]      (docker DNSNames: "postgres")
  ip: 172.18.0.2  (DHCP — NOT stable, MUST NOT be used as the value)
  host_port_publish: 127.0.0.1:5432:5432  (loopback only)
  compose_internal_port: 5432
established_convention (other services on docker_incomex reaching PG):
  incomex-directus :  DB_HOST: postgres   DB_PORT: '5432'
  incomex-agent-data: DIRECTUS_DB_HOST: postgres / PG_HOST: postgres
                      DB/PG_PORT: '5432'
cutter_agent_service_in_compose: NONE (no cutter/iu-cutter/dot-agent service
  defined yet — runtime binding is a later gated cycle, DA-6)

Recommended host rationale (non-guess): every existing service that talks to PostgreSQL on this stack resolves it by the docker-network DNS name postgres on port 5432 (verified container alias + DNSName + two sibling services' config). The cutter-agent's only coherent runtime context — given its credentials already live in this compose stack's .env — is a service on docker_incomex, where postgres/5432 is the proven, topology-derived endpoint. The container IP (172.18.0.2) is explicitly rejected (DHCP, unstable). The loopback publish (127.0.0.1:5432) is rejected as the value because it only works for a host-process context, which contradicts the compose-substrate placement and the design's no-localhost-fallback rule; if a host-process runtime is later chosen, that is a deviation to be raised at the runtime-binding command-review (DA-6), not assumed here.

§3a — FR-1 Resolution: Production PostgreSQL SSL Status (read-only)

GPT required FR-1 (sslmode value) be resolved before any .env write, because DOT_CUTTER_DB_SSLMODE directly determines whether the future RealPostgresAdapter can connect at all. Resolved here by read-only inspection of the production postgres container — no connect, no auth, no secret, nothing changed.

Evidence (VPS 38.242.240.89, container postgres, image postgres:16, network docker_incomex — the same PG these env keys target):

  1. docker ps → production PG container is named postgres (image postgres:16). (Sibling pg-dry-run-* containers are unrelated ephemeral dry-run envs; not inspected for this decision.)

  2. Server SSL settings via read-only pg_settings query as the container's own directus role (POSTGRES_USER=directus; no postgres superuser role exists; no password printed):

    ssl           | off
    ssl_ca_file   | (empty)
    ssl_cert_file | server.crt      ← default config NAME only
    ssl_key_file  | server.key      ← default config NAME only
    ssl_library   | OpenSSL         ← compiled-in, but NOT enabled
    
  3. Cert/key file presence in the data dir:

    ls /var/lib/postgresql/data/server.crt → No such file or directory
    ls /var/lib/postgresql/data/server.key → No such file or directory
    

    The ssl_cert_file/ssl_key_file settings are merely PostgreSQL's built-in default names; the actual files do not exist. Even if ssl were flipped on, the server has no certificate/key to present.

Determination:

ssl_enabled: NO            (pg_settings ssl = off)
cert_key_present: NO       (server.crt / server.key absent from data dir)
ssl_library_compiled: yes  (OpenSSL — capability exists, NOT configured)
intra_docker_sslmode_require_usable: NO
  rationale: with server ssl=off, a libpq/psycopg client connecting with
  sslmode=require is REJECTED (require = SSL-only, no fallback). Sibling
  services (incomex-directus, incomex-agent-data) already connect to this
  PG over the docker_incomex private bridge WITHOUT TLS — confirming the
  established, working transport for this stack is plaintext on the
  internal bridge.

FR-1 decision: SSL is off and not usable on production PG. Per the resolution rule, DOT_CUTTER_DB_SSLMODE is changed from requiredisable for the v0.4 internal docker-bridge runtime. This matches the proven sibling-service transport (private bridge, no TLS) and ensures the future RealPostgresAdapter can actually connect.

Forward hardening note (NOT a v0.4 blocker): server-side TLS (generate/mount server.crt+server.key, set ssl=on) followed by client sslmode=verify-full + CA pinning remains a future hardening track, out of scope for v0.4. It would be its own gated design+command-review cycle and would re-revise this key at that time. FR-1 is CLOSED for v0.4 by selecting disable.

§4 — Exact Proposed .env Additions (NO password values)

Appended verbatim to /opt/incomex/docker/.env (one trailing block):

Key Proposed value Source / authority
DOT_CUTTER_DB_HOST postgres discovered topology §3 (docker DNS alias; matches directus/agent-data)
DOT_CUTTER_DB_PORT 5432 compose internal port; sibling-service convention; pending C-04 preflight
DOT_CUTTER_DB_NAME directus GPT DA-1/§8 (cutter_governance schema lives in db directus)
DOT_CUTTER_DB_SSLMODE disable FR-1 resolved §3a — prod PG ssl=off, no cert/key; require unusable; matches sibling no-TLS bridge transport (supersedes r1 require/DA-2; verify-full = future hardening)
# --- dot-iu-cutter v0.4 connection components (non-secret; added 2026-05-17) ---
DOT_CUTTER_DB_HOST=postgres
DOT_CUTTER_DB_PORT=5432
DOT_CUTTER_DB_NAME=directus
DOT_CUTTER_DB_SSLMODE=disable

All four are non-secret. No DOT_CUTTER_DB_DSN is added (design forbids DSN-with-password). No credential key is read, rewritten, or reordered.

FR-1 status: RESOLVED & CLOSED for v0.4 (see §3a). The r1 forward-risk is no longer open; sslmode=disable is consistent with the verified server state and the working sibling-service transport. Future server TLS

  • verify-full is tracked as a separate future-hardening cycle, not a v0.4 connection-time risk.

§5 — Proposed Command Sequence (REVIEW TARGET — NOT executed)

UNCHANGED from r1. Only the §4 DOT_CUTTER_DB_SSLMODE value differs (requiredisable); C-06 still appends the §4 block verbatim and C-07 still asserts the §4 values — which now carry disable.

command_count: 8  (C-01..C-07 forward + C-08 conditional rollback)

C-01 preflight perms : stat -c '%a %U:%G' /opt/incomex/docker/.env
       == "600 root:root"  else ABORT (gate G-1). [read-only]
C-02 preflight creds : assert the 4 credential key NAMES present
       (grep -c by name; values NEVER read). any missing → ABORT (G-2).
C-03 preflight absent: grep -cE '^DOT_CUTTER_DB_(HOST|PORT|NAME|SSLMODE)='
       == 0  else ABORT (G-4 duplicate/conflict).
C-04 preflight host  : from the INTENDED runtime context (ephemeral
       throwaway container on docker_incomex, e.g.
       `docker run --rm --network docker_incomex busybox \
         nslookup postgres`) confirm `postgres` resolves AND port 5432 is
       the intended endpoint; cannot resolve → ABORT (G-3). Read-only DNS
       probe ONLY — does NOT connect to PostgreSQL, no auth, no .env read.
C-05 backup          : cp -p /opt/incomex/docker/.env \
       /opt/incomex/docker/.env.bak.<UTCSTAMP> ; record sha256 of both
       (pre-change integrity anchor). perms preserved 600 root:root.
C-06 apply           : append EXACTLY the 4-line block from §4 (idempotent —
       guarded by C-03; no in-place rewrite of any existing line; no
       secret echoed; no `set -x`).
C-07 verify          : assert exactly the 4 new keys present with the §4
       values (incl. DOT_CUTTER_DB_SSLMODE=disable); assert the credential
       key NAME set == pre-set ∪ {4 new} (no credential key added/removed/
       renamed); assert NO password value appears in any log/console
       (grep guard, names-only); perms still 600 root:root; .env line
       count == pre + 5 (4 keys + 1 comment). any check fails → C-08.
C-08 rollback (cond.) : ON C-07 failure or integrity mismatch — restore
       /opt/incomex/docker/.env from the C-05 backup (full restore) OR, if
       backup intact and only the appended block is the delta, remove ONLY
       the 4 newly added non-secret keys + their comment line. Re-assert
       perms 600 root:root and credential-name-set unchanged. Never edits
       credential lines.

§6 — Safety Gates (abort conditions)

UNCHANGED from r1.

G-1 .env permissions ≠ 600 root:root                       → ABORT (C-01)
G-2 any of the 4 credential keys missing                    → ABORT (C-02)
G-3 proposed host cannot resolve from intended runtime ctx  → ABORT (C-04)
G-4 any pre-existing/duplicate/conflicting DOT_CUTTER_DB_*   → ABORT (C-03)
G-5 any secret value would be printed/logged/echoed         → ABORT (all C;
      commands use name-only greps, no `set -x`, no value interpolation)
G-6 post-apply credential-key NAME set changed              → ROLLBACK (C-08)
G-7 post-apply perms drifted from 600 root:root             → ROLLBACK (C-08)
G-8 backup sha mismatch on restore                          → ROLLBACK to
      C-05 backup; if backup itself corrupt → STOP + NEEDS_HUMAN

§7 — Rollback Plan

UNCHANGED from r1.

pre_change_anchor: C-05 timestamped backup of .env (perms-preserving cp -p,
  600 root:root) + sha256 of pre and post.
trigger: C-07 verify failure | G-6 | G-7 | integrity/sha mismatch.
action_primary: full restore of /opt/incomex/docker/.env from the C-05
  backup (byte-identical → credential keys exactly as before).
action_minimal: if backup verified intact and the ONLY delta is the §4
  appended block, remove just the 4 added non-secret keys + the comment
  line; re-verify credential-name-set + perms.
never: edit/rewrite/reorder any credential line; print any secret value;
  delete the backup until GPT confirms closeout.
post_rollback_state: .env == pre-change (4 connection keys absent again);
  no credential change; perms 600 root:root.

§8 — Non-Scope (explicitly excluded from this cycle)

- no role / GRANT / privilege change
- no secret rotation, no password read/print/derive
- no code change (commit 689e53e untouched; ProductionDBAdapter still refuses)
- no runtime DB connection; no adapter binding
- no service restart; no compose up/recreate; no deploy
- no dry-run (in-memory or PG-backed)
- no CUT / VERIFY
- no server-side TLS enablement / cert generation (future hardening track)
- adding a service to docker-compose / choosing final runtime container =
  deferred to runtime-binding command-review (DA-6) — NOT here

§9 — Output Summary

command_count: 8 (C-01..C-07 forward + C-08 conditional rollback)
proposed_keys:
  DOT_CUTTER_DB_HOST=postgres
  DOT_CUTTER_DB_PORT=5432
  DOT_CUTTER_DB_NAME=directus
  DOT_CUTTER_DB_SSLMODE=disable        # r2: FR-1 resolved (was require in r1)
fr_1_resolution:
  prod_pg_ssl: off (pg_settings ssl=off; ssl_ca_file empty)
  cert_key_files: ABSENT (server.crt / server.key not in data dir)
  ssl_library: OpenSSL compiled-in but NOT configured
  sslmode_require_usable: NO (server ssl=off rejects require; no fallback)
  decision: DOT_CUTTER_DB_SSLMODE=disable for v0.4 internal docker bridge
  matches: sibling incomex-directus / incomex-agent-data no-TLS bridge transport
  future_hardening: server TLS + client verify-full = separate gated cycle
  fr_1_status: RESOLVED & CLOSED for v0.4
discovered_host_rationale: docker-network DNS alias `postgres` on
  docker_incomex — verified container alias/DNSName + the convention used by
  incomex-directus and incomex-agent-data; container IP & loopback publish
  explicitly rejected; not guessed.
safety_gates: G-1..G-8 (perms / creds-present / host-resolves /
  no-duplicate / no-secret-print / creds-unchanged / perms-stable /
  backup-integrity)  [UNCHANGED from r1]
rollback_plan: C-05 timestamped perms-preserving backup → full restore or
  minimal 4-key removal; credential lines never touched  [UNCHANGED from r1]
delta_from_r1: ONLY DOT_CUTTER_DB_SSLMODE require → disable + FR-1 closed;
  command sequence / gates / rollback / non-scope unchanged
execution_status: BLOCKED — NOTHING EXECUTED; .env UNCHANGED; no secret
  read; read-only topology + read-only PG SSL inspection only
ready_for_gpt_review: YES
agent_self_advance: PROHIBITED

End of v0.4 connection env keys command-review package r2 (FR-1 resolved → sslmode=disable; command-review only; not executed; .env unchanged; no secret read; next = GPT review of r2).

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.4-db-adapter-execution/dot-iu-cutter-v0.4-connection-env-keys-command-review-package-2026-05-17.md