From 7d6d90f4863eb92cbdf6fab4a857ed699fb59cad Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 17:09:55 +1000 Subject: [PATCH] Add an open-issues register, and correct what port 8443 actually is status/OPEN-ISSUES.md is a fourth register, so it opens by saying what does NOT belong in it. Work blocked on other people stays in REQUESTS.md; shortcuts we consciously accepted stay in BUILD-AI-CONTAINERS.md 14 and are closed by decision, not to be re-raised here; what is running stays in current-state.html. What had no home until now is a defect we own and have not fixed - those were living in commit messages. Closed issues move to the bottom rather than being deleted: this repo is an as-built record, and an issue with no trace of how it closed is worth less than one that was never raised. OI-01: the OpenPLC Editor is not installed anywhere. It is a desktop tool published by OpenPLC, and it is what authors and compiles the IEC 61131-3 program openplc-runtime executes. Without it there is no reviewable source for the control logic in or beside this repository - the program exists only inside the container. Raising it exposed two wrong statements in the build spec, both calling port 8443 the "OpenPLC Runtime web UI". Probed read-only on the host: Server: Werkzeug/3.1.8 Python/3.11.2 / /login /index.html /programs /status /runtime -> 404 /api/v1 -> 401 Unauthorized It is an authenticated REST API with no browser interface at all. Section 4 now says so with the evidence, and 14's entry is restated: 8443 is contained by the same 10.0.0.17 binding as 502, but unlike 502 it is not anonymous, which is a better position than that section recorded. The binding is still the control that matters. Co-Authored-By: Claude Opus 5 --- README.md | 2 + spec/BUILD-AI-CONTAINERS.md | 12 ++++-- status/OPEN-ISSUES.md | 76 +++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 status/OPEN-ISSUES.md diff --git a/README.md b/README.md index 615e6a5..2e2f86e 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ Then, depending on what you came to do: | Understand *why* it is built this way | [`spec/BUILD-AI-CONTAINERS.md`](spec/BUILD-AI-CONTAINERS.md) | | Understand the host it runs on | [`spec/YAU_Linux_Host_Onboarding.md`](spec/YAU_Linux_Host_Onboarding.md) | | Know what is still blocked, and on whom | [`status/REQUESTS.md`](status/REQUESTS.md) | +| Know what is broken or unfinished, and ours to fix | [`status/OPEN-ISSUES.md`](status/OPEN-ISSUES.md) | | Change code | `pytest api/tests` first — it needs no network, no API key and no database | **You will need**, and should confirm before starting: SSH to `lin001`, an AD @@ -227,6 +228,7 @@ status/ where it got to — snapshots, go stale, edited oft an answer, and what is built. Open it in a browser current-state.html what is actually running right now. Open it too REQUESTS.md what is still needed from other people + OPEN-ISSUES.md what is broken or unfinished, and ours to fix compose/ deployed to ~/ai-compose.yml and ~/langfuse-compose.yml caddy/ai-routes.caddy blocks to paste into ~/Caddyfile diff --git a/spec/BUILD-AI-CONTAINERS.md b/spec/BUILD-AI-CONTAINERS.md index 9e02da9..125add7 100644 --- a/spec/BUILD-AI-CONTAINERS.md +++ b/spec/BUILD-AI-CONTAINERS.md @@ -86,8 +86,14 @@ Consequences worth knowing: So it is published on the VNet interface only and is not internet-reachable at the Docker level, whatever the NSG says. That is a stronger position than this document originally assumed, and it is the reason the NSG item in §15 is now a confirmation - rather than an open risk. **`openplc-runtime` also publishes 8443** — the OpenPLC - Runtime web UI — on the same private address; earlier drafts did not mention it. + rather than an open risk. **`openplc-runtime` also publishes 8443** on the same + private address; earlier drafts did not mention it. **It is a REST API, not a web + UI** — earlier drafts of this document said web UI and were wrong. Probed read-only + on the host 2026-09-01: `Server: Werkzeug/3.1.8 Python/3.11.2`, `/`, `/login`, + `/index.html`, `/programs`, `/status` and `/runtime` all `404`, and `/api/v1` + returns `401`. There is no browser interface on that port. The OpenPLC **Editor** — + a separate desktop tool published by OpenPLC, installed on a workstation — is what + talks to it, and it is not installed anywhere yet (`status/OPEN-ISSUES.md` OI-01). - **Port 502 still has no authentication and no encryption.** Modbus never has. The binding above is what contains it, so anything that changes the binding to `0.0.0.0`, or any NSG rule that exposes the VNet address, removes the only control on it. @@ -802,7 +808,7 @@ it is the same derivation that will run against `imh`. - **`ai.yokogawa.tech` is unauthenticated from `cicore1`.** Applied 2026-08-28 at the customer's direction: an on-site operator should not complete a Duo push to ask a question, and nobody outside the plant should reach the assistant at all. The Caddy block admits `remote_ip 10.0.0.21` only and returns 403 to everything else, `import authelia` removed from that branch. This is an IP allowlist on a flat network with no OT/IT boundary — anything that can take `10.0.0.21`, or ARP-spoof it, inherits unauthenticated access to every answer the assistant can give. It is a demo affordance, **not a security control**, and it is the first thing network segmentation closes. Two consequences worth stating separately: Langfuse traces are now anonymous, so there is no record of who asked what; and the assistant is unreachable by browser from the VPN, so engineers need an SSH tunnel. **A third, found 2026-08-31: there is no usage record at the edge either.** The Caddy block has no `log` directive — no site on this host does — so the front door logs nothing, and the only evidence that the console has ever been used is `ai-web`'s container log, which `docker compose up -d --force-recreate` wipes. That is how a working operator path sat unnoticed for three days while the repo recorded it as unproven. **Access logging was considered and declined on 2026-09-01.** The ephemeral evidence is accepted: usage is confirmed as at 31 August and recorded in Phase 7's gate, and if the container is recreated that confirmation stands on the record here rather than in a log. Do not re-raise this as a task. `api.yokogawa.tech` is unchanged and still fully gated — Phase 9 document publishing depends on that and must stay there - Public egress to Azure OpenAI, no private endpoint - Chromium running on the SCADA VM itself -- Modbus TCP on port 502 with no authentication or encryption — inherent to the protocol; contained by its bind to `10.0.0.17` plus NSG/VPN scope. The OpenPLC Runtime web UI on 8443 is contained the same way and nothing else +- Modbus TCP on port 502 with no authentication or encryption — inherent to the protocol; contained by its bind to `10.0.0.17` plus NSG/VPN scope. Port 8443 on the same container is contained the same way and nothing else — but unlike 502 it is **not** anonymous: it serves a REST API under `/api/v1` that answers `401` unauthenticated, and there is no web UI on it (verified 2026-09-01, §4). That is a better position than earlier drafts of this document recorded, and the binding is still the control that matters: nothing on this container should ever move to `0.0.0.0` - Single host, no HA — `lin001` is now a single point of failure for **both** the demo estate and the simulated plant's PLC - Shared `azureuser` login; no per-person audit trail on the host - Shared service account to `imh`; no per-operator row-level security diff --git a/status/OPEN-ISSUES.md b/status/OPEN-ISSUES.md new file mode 100644 index 0000000..adb0f11 --- /dev/null +++ b/status/OPEN-ISSUES.md @@ -0,0 +1,76 @@ +# Open issues — WRPS Plant Assistant + +**Work we own, know about, and intend to do.** One entry per issue, newest first. +Nothing here is assigned yet; owners are set at handover. + +## What belongs here, and what does not + +This repository has three other registers. Putting an item in the wrong one is how +a repository ends up saying two different things about the same fact. + +| If it is... | It goes in | Not here | +|---|---|---| +| Waiting on somebody outside this project | [`REQUESTS.md`](REQUESTS.md) | ✗ | +| A shortcut we **consciously accepted** | [`BUILD-AI-CONTAINERS.md`](../spec/BUILD-AI-CONTAINERS.md) §14 | ✗ | +| Something already running, and its state | [`current-state.html`](current-state.html) | ✗ | +| **A defect or gap we own and have not fixed** | **here** | ✓ | + +Three rules: + +1. **Anything in §14 is closed by decision.** It was weighed and accepted. Do not + re-open it here — `caddy/ai-routes.caddy` carries one such decision explicitly + marked *"do not re-raise this as a task"*. +2. **If an issue is a defect in something that already passed a phase gate**, fixing + it means re-running that gate. `CLAUDE.md` requires it; say so in the issue. +3. **Closed issues move to the bottom, they are not deleted.** The register is part + of the as-built record, and an issue with no trace of how it closed is worth less + than one that was never raised. + +--- + +## Open + +### OI-01 · OpenPLC Editor is not installed + +**Raised** 2026-09-01 · **Owner** unassigned · **Affects** the demo plant, not the assistant + +The **OpenPLC Editor** — a desktop tool published by the OpenPLC project, installed on a +workstation — is the application used to author and compile the IEC 61131-3 program that +`openplc-runtime` executes. It is not installed anywhere. It talks to the running container +over its REST API on port `8443`, bound to `10.0.0.17`. + +**Why it matters.** `openplc-runtime` is live control for this demo: `CLAUDE.md` and +[`BUILD-AI-CONTAINERS.md`](../spec/BUILD-AI-CONTAINERS.md) §4 both forbid reconfiguring it +as a side effect of other work. Without the Editor there is no way to author, review or +compile the control logic — and no reviewable source for it in or beside this repository. +The program exists only inside the container. If the container is lost, so is the logic. + +**What port 8443 is** — probed read-only on the host 2026-09-01, because two earlier +statements in the build spec called it a web UI and were wrong: + +``` +Server: Werkzeug/3.1.8 Python/3.11.2 +/ /login /index.html /programs /status /runtime -> 404 +/api/v1 -> 401 Unauthorized +``` + +An authenticated REST API. No browser interface. Both build-spec statements were corrected +in the commit that raised this issue. + +**Open questions to settle when this is picked up.** + +- **Which workstation.** Not `lin001` — the Editor is a desktop application. Not `cicore1` — + `CLAUDE.md` forbids installing anything on it. That leaves an engineering workstation with + VPN or LAN reach to `10.0.0.17:8443`. +- **Credentials for `/api/v1`**, which currently answers `401`. Not held by this project. +- **Whether the PLC program goes under version control**, and where. This is the part that + closes the "logic exists only in the container" gap, and it is the reason this issue is + worth more than "install a tool". + +**Blocked by** nothing. **Blocking** nothing today — the demo runs. + +--- + +## Closed + +*None yet. Closed issues move here with the commit that closed them.*