R-902 search: contact-mailer source NOT FOUND (DooPlex disks, web editor + history, 10 Gitea repos, build cache); binary kept in git; replacement plan; decoy suite takes a lock (two sessions' runs left a decoy planted)
gates / gates (push) Failing after 11m42s
gates / gates (push) Failing after 11m42s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
# REPORT — the contact mailer's lost source (R-902), 2026-10-08
|
||||
|
||||
**NOT FOUND.** Searched read-only on DooPlex, in the web editor, in all Gitea repositories and in Docker's build
|
||||
records. The running binary is now kept in git; a replacement plan is written (Part D).
|
||||
|
||||
> `REPORT-mailer-source.md`, not `REPORT.md`: another session has uncommitted work in this repo.
|
||||
|
||||
## Part A — the program's clues (`documentation/audits/mailer-source-2026-10-08/`)
|
||||
|
||||
- `go version -m`: module `github.com/felhom/contact-mailer (devel)`, **go1.23.12**, `CGO_ENABLED=0`, `-ldflags="-w -s"`.
|
||||
**No `vcs.revision`/`vcs.time`/`vcs.modified`.**
|
||||
- Build paths in the binary: **`/build/main.go`** only — one source file, built in a container folder.
|
||||
- Image (containerd, `k3s ctr content get`): built **2026-02-05 10:40 +01:00** by BuildKit, two stages (builder at
|
||||
`/build`; alpine 3.20.9, user 1000, `WORKDIR /app`, `COPY /build/contact-mailer .`). The SLSA provenance blob the
|
||||
index names is not present in containerd.
|
||||
|
||||
## Part B — places searched, each with its positive control
|
||||
|
||||
| Place | Found | Control that proves the search worked |
|
||||
|---|---|---|
|
||||
| `/build` (from Part A) | does not exist on DooPlex | — |
|
||||
| Web editor storage + its file history (through the running pod) | only `felhom.eu/manifests/contact-mailer.yaml` | `func main` found in agent code and in 2 History copies |
|
||||
| All 10 Gitea repos, full history (`-G sendViaResend\|buildEmailHTML\|felhom/contact-mailer`) | manifests only (homelab-manifests c9648cd 2026-02-05; felhom.eu 0b144a4d) | the manifests are found by the same search |
|
||||
| DooPlex disks, 55,548 `*.go`/`go.mod`/`Dockerfile*` files + name search, no depth limit | only `hub/cmd/hub/main.go` (×2, for `RESEND_API_KEY`) and the pod's logs | `RESEND_API_KEY` in the hub's main.go |
|
||||
| Docker build cache (337 records) and build history | oldest record 2026-09-28; history 7 days | today's builds are listed |
|
||||
|
||||
Excluded by name: kernel/runtime folders, Docker/containerd/k3s/kubelet/Longhorn/PBS stores, media folders — listed in
|
||||
`SEARCH.md`. Not reachable: the operator's Windows workstation.
|
||||
|
||||
**Side finding:** `homelab-manifests` history (c9648cd) holds an old Resend key literal. Compared by hash only, it is
|
||||
not today's key (rotated 2026-06-29, felhom.eu feea0606). Whether the old key was also revoked at Resend is not visible
|
||||
from here. No row.
|
||||
|
||||
## Part D — the plan
|
||||
|
||||
`documentation/audits/mailer-source-2026-10-08/PLAN-replacement.md`: endpoints (`/api/contact`, `/healthz`,
|
||||
`/debug/test`), env, one mail per form with Reply-To, the limits read from the binary (5 files, 10 MB each, 20 MB
|
||||
total, name ≤ 200, message ≤ 10 000, rate limit, honeypot), a stdlib-only replacement with a version-tagged image,
|
||||
proof steps, switch-over and roll-back.
|
||||
|
||||
**The binary is committed** (`contact-mailer.bin`, sha256 `775a23d5…30bb0`, no key inside — searched): a DooPlex
|
||||
rebuild no longer loses the program.
|
||||
|
||||
## Fixed without a row: the decoy suite now runs one at a time
|
||||
|
||||
During this task the gates ran in this session and in Felhom.eu session 1 at the same moment. `scripts/test_gate_decoys.py`
|
||||
edits real files and restores them from a copy taken when it plants; two runs at once left a planted fault behind —
|
||||
`website/en/apps.html` lost its Radicale logo line, twice, in the local copy (never pushed; the live page was checked:
|
||||
logo present). Restored from HEAD both times. The suite now takes an exclusive lock (`.git/decoy-suite.lock`) at start,
|
||||
so a second run waits; two runs of mine started 2 s apart both finished, one after the other (the waiting one: „all 73
|
||||
decoys behaved"). The other session could not be messaged (not reachable from here).
|
||||
|
||||
## Register
|
||||
|
||||
Rows before **130**, after **130**, opened **0**, closed **0**. R-902 stays open, NARROWED (search done; owner operator).
|
||||
|
||||
## One decision for you
|
||||
|
||||
Is the February `contact-mailer` folder on your Windows workstation (for example under `e:\DooPlex Server\`)?
|
||||
- **Pick: look there first.** If it is there, I commit it as it is and only a tagged rebuild is left.
|
||||
- **If you do nothing:** the replacement is written from the plan in a later, attended task. The form keeps working.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Plan — a replacement for the contact mailer (R-902)
|
||||
|
||||
The February source is lost (`SEARCH.md`). The running program keeps working; this plan is for a later, attended
|
||||
session. **Nothing here is built or deployed yet.**
|
||||
|
||||
## What the running program does (read from the binary and the manifest — not from source)
|
||||
|
||||
- **Endpoints:** `POST /api/contact` (the Ingress sends `felhom.eu/api/*` here), `GET /healthz` (the probes),
|
||||
`POST /debug/test` (only when `DEBUG=true`; the manifest sets `false`). Listens on `LISTEN_ADDR`, default `:8080`.
|
||||
- **Env:** `RESEND_API_KEY` (from `Secret/resend-api`), `FROM_EMAIL`, `TO_EMAIL`, `ALLOWED_ORIGIN`, `TZ`, `DEBUG`.
|
||||
- **Per form, one mail** via `https://api.resend.com/emails` (Bearer key): from `FROM_EMAIL`, to `TO_EMAIL`,
|
||||
`reply_to` = the visitor, HTML table (`buildEmailHTML`: header „Új üzenet a weboldalról", rows incl. Tárgy,
|
||||
„Csatolmány … %d fájl"), attachments as base64. **Nothing is sent to the visitor.**
|
||||
- **Checks, with Hungarian JSON errors:** CORS to `ALLOWED_ORIGIN`; a per-IP rate limiter („Túl sok kérés…"); a
|
||||
honeypot field `website`; required fields („Kérlek, töltsd ki az összes kötelező mezőt."); name ≤ 200, message
|
||||
≤ 10 000 characters; e-mail format and length; at most 5 files, ≤ 10 MB each, ≤ 20 MB together; a malformed or
|
||||
too-large request („A kérés mérete túl nagy vagy hibás formátum."). The page shows its own messages, not these.
|
||||
|
||||
## The replacement
|
||||
|
||||
One `main.go` (stdlib only, Go ≥ 1.23), same endpoints, env, limits and mail shape; the rate limit and the
|
||||
template copied from the strings above. Committed to `felhom.eu/contact-mailer/` with `go.mod`, a two-stage
|
||||
`Dockerfile` (the same shape the image record shows: builder at `/build`, alpine runtime, user 1000, `/app`), tests
|
||||
for each refusal, and a `README.md`. The image is built **with a version tag** and pushed to the Gitea registry,
|
||||
so `imagePullPolicy: Never` and the hand import end; the manifest names that tag.
|
||||
|
||||
## How to prove it, before switching
|
||||
|
||||
1. Unit tests: every refusal above, and the mail body built from a sample form (no network).
|
||||
2. A second Deployment `contact-mailer-next` (no Ingress), port-forwarded: a real form with one small PDF → one mail
|
||||
arrives at info@ with Reply-To = the sender and the attachment; an 11 MB file → refused; six files → refused.
|
||||
3. Compare its mail with one from the running program (same fields, same subject line).
|
||||
|
||||
## Switch-over (attended)
|
||||
|
||||
Point the Deployment at the new tag, wait for Ready, send one form from `felhom.eu/kapcsolat` and one from
|
||||
`/en/contact`, read both mails. Roll back = the old manifest line (the old image stays in containerd, and its binary
|
||||
is kept in `documentation/audits/mailer-source-2026-10-08/contact-mailer.bin`).
|
||||
|
||||
## One question for the operator
|
||||
|
||||
Do you still have the February folder on your Windows workstation (`e:\DooPlex Server\…` or a „contact-mailer"
|
||||
folder)? **Pick: look there first** — if it is there, it is committed as it is and this plan shrinks to „rebuild with
|
||||
a version tag". **If you do nothing:** the replacement is written from this page in a later website/ops task.
|
||||
@@ -0,0 +1,44 @@
|
||||
# The contact mailer's source — the search (2026-10-08)
|
||||
|
||||
**Result: NOT FOUND.** Read only on DooPlex: no restart, no deploy, no image tag, no change to the pod.
|
||||
|
||||
## Part A — the program's own clues
|
||||
|
||||
| Clue | Value | Source |
|
||||
|---|---|---|
|
||||
| Module | `github.com/felhom/contact-mailer` `(devel)` | `go version -m` → `go-version-m.txt` |
|
||||
| Go | go1.23.12, `CGO_ENABLED=0`, `-ldflags="-w -s"` | same |
|
||||
| `vcs.revision` / `vcs.time` / `vcs.modified` | **absent** — not built inside a git folder (or with VCS stamping off) | same |
|
||||
| Source file | **one file: `/build/main.go`** (the only non-stdlib `.go` path in the binary) | `strings` |
|
||||
| Image | `docker.io/library/contact-mailer:latest`, index `sha256:fac420fd…`, built **2026-02-05 10:40 +01:00** by BuildKit; multi-stage: a builder stage with `/build`, then alpine 3.20.9 + `ca-certificates tzdata`, user `appuser` 1000, `WORKDIR /app`, `COPY /build/contact-mailer .` | `k3s ctr content get` → `image-config.json` |
|
||||
| Provenance | the index names an SLSA provenance blob (`sha256:f4ad3f62…`) — **not present** in containerd (`ctr content get`: not found) | — |
|
||||
|
||||
The binary itself is kept here (`contact-mailer.bin`, sha256 in `contact-mailer.bin.sha256`; no API key inside — a
|
||||
search for `re_…`, `Bearer re_`, `sk-`, `ghp_` found 0): if DooPlex is rebuilt, this is the only copy of the program.
|
||||
|
||||
## Part B — where it was searched (each with its positive control)
|
||||
|
||||
| # | Place | Result | Positive control |
|
||||
|---|---|---|---|
|
||||
| 1 | Paths from Part A (`/build`) | none on DooPlex (`/build` does not exist; it was the build container's folder) | — |
|
||||
| 2 | Web editor (`code-system/code-server`, Longhorn PVCs `code-server-workspace`/`-config`/`-local`, read through the running pod): `grep -r` for `sendViaResend`, `buildEmailHTML`, `felhom/contact-mailer` in `*.go`, `go.mod`, `Dockerfile*` under `/home/coder`; name search `*contact*mailer*`; the editor's file history `~/.local/share/code-server/User/History` (34 MB) without a type filter | only `felhom.eu/manifests/contact-mailer.yaml` | `func main` found in `felhom-agent/cmd/felhom-opsign/main.go` and in two History `.go` copies |
|
||||
| 3 | Gitea: all 10 repositories the two tokens see (`admin/*`; no other owner visible), full history, `git log --all -G 'sendViaResend\|buildEmailHTML\|felhom/contact-mailer'` | hits only in manifests: `homelab-manifests` c9648cd (2026-02-05 „added mailer pod", deleted ee93b50) and `felhom.eu` 0b144a4d | the same search finds the manifests (which name `…/felhom/contact-mailer`) |
|
||||
| 4 | DooPlex disks, whole (`/`, `/mnt/1_hdd`, `2_hdd`, `3_hdd`, `5_hdd`, `ssd_2`), `nice -n 19 ionice -c3`: name search `*contact-mailer*`/`*contact_mailer*`, no depth limit; content search of 55,548 `*.go`/`go.mod`/`Dockerfile*` files for `sendViaResend\|buildEmailHTML\|felhom/contact-mailer\|RESEND_API_KEY\|contact-mailer\|contact_mailer` (`search.sh`, `disk-search.txt`) | names: the manifest and the pod's own logs only; content: only `hub/cmd/hub/main.go` (×2) | `RESEND_API_KEY` found in the hub's `main.go` (both copies) |
|
||||
| 5 | Docker build cache (`docker buildx du --verbose`, 337 records) and build history (`docker buildx history ls`) | oldest cache record 2026-09-28, history 7 days — the February build is gone; no dangling image | the lists hold today's builds |
|
||||
|
||||
**Excluded by name** (fences or no source possible): `/proc /sys /dev /run`, `/var/lib/{docker,containerd,
|
||||
containerd.pre-move-2026-08-05,rancher,kubelet,longhorn,proxmox-backup}`, `/mnt/ssd_2/{replicas,containerd}`,
|
||||
`/mnt/backup-longhorn`, any `.chunks` (PBS), media folders (`Download Series Movies Cartoons Kids Audiobook Photos
|
||||
Videos "Phone Backup"`, `/mnt/plex_media`), `lost+found`, the session scratchpad. Gitea's and the registry's own
|
||||
storage live in k3s/Longhorn volumes and were not read directly (Gitea was read through its API).
|
||||
|
||||
**Not reachable from here:** the operator's Windows workstation (`e:\DooPlex Server\` holds DooPlex deploy notes per
|
||||
project memory). The manifest's own comment says `docker build -t contact-mailer:latest .`, then
|
||||
`docker save … | sudo k3s ctr images import -` — a build on a machine with k3s, so DooPlex, from a folder that no
|
||||
longer exists here.
|
||||
|
||||
## A side finding
|
||||
|
||||
`homelab-manifests` history (c9648cd, 2026-02-05) holds a Resend API key literal in the old manifest's comment. Compared
|
||||
by hash only (never printed): it is **not** today's key (`Secret/resend-api`), which was rotated 2026-06-29 (felhom.eu
|
||||
feea0606). No row: the key was already replaced.
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
775a23d53c2b28040ae864de439c78d045fd46a046bcefea3b9f15f936830bb0 /mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/audits/mailer-source-2026-10-08/contact-mailer.bin
|
||||
@@ -0,0 +1,11 @@
|
||||
# name search
|
||||
/mnt/5_hdd/felhom.eu/git/felhom.eu/manifests/contact-mailer.yaml
|
||||
/var/log/containers/contact-mailer-5bb869b85b-pqtjt_felhom-system_contact-mailer-69fe37a42882d3860e5a2f0ce78332e5a6c8300000527559bb2bc457d7376c64.log
|
||||
/var/log/pods/felhom-system_contact-mailer-5bb869b85b-pqtjt_94e8810a-d124-49b6-96e3-863c7966a343
|
||||
/var/log/pods/felhom-system_contact-mailer-5bb869b85b-pqtjt_94e8810a-d124-49b6-96e3-863c7966a343/contact-mailer
|
||||
# content search (*.go, go.mod, Dockerfile*)
|
||||
/mnt/5_hdd/felhom.eu/build/felhom-hub/workspace/cmd/hub/main.go
|
||||
/mnt/5_hdd/felhom.eu/git/felhom.eu/hub/cmd/hub/main.go
|
||||
# count of files content-searched
|
||||
55548
|
||||
# done
|
||||
@@ -0,0 +1,10 @@
|
||||
/mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/audits/mailer-source-2026-10-08/contact-mailer.bin: go1.23.12
|
||||
path github.com/felhom/contact-mailer
|
||||
mod github.com/felhom/contact-mailer (devel)
|
||||
build -buildmode=exe
|
||||
build -compiler=gc
|
||||
build -ldflags="-w -s"
|
||||
build CGO_ENABLED=0
|
||||
build GOARCH=amd64
|
||||
build GOOS=linux
|
||||
build GOAMD64=v1
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"created": "2026-02-05T10:40:02.940564676+01:00",
|
||||
"config": {
|
||||
"User": "appuser",
|
||||
"ExposedPorts": {
|
||||
"8080/tcp": {}
|
||||
},
|
||||
"Env": [
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
],
|
||||
"Entrypoint": [
|
||||
"./contact-mailer"
|
||||
],
|
||||
"WorkingDir": "/app"
|
||||
},
|
||||
"history": [
|
||||
{
|
||||
"created": "2026-01-28T01:18:16.507489867Z",
|
||||
"created_by": "ADD alpine-minirootfs-3.20.9-x86_64.tar.gz / # buildkit",
|
||||
"comment": "buildkit.dockerfile.v0"
|
||||
},
|
||||
{
|
||||
"created": "2026-01-28T01:18:16.507489867Z",
|
||||
"created_by": "CMD [\"/bin/sh\"]",
|
||||
"comment": "buildkit.dockerfile.v0",
|
||||
"empty_layer": true
|
||||
},
|
||||
{
|
||||
"created": "2026-02-05T10:39:46.98938696+01:00",
|
||||
"created_by": "RUN /bin/sh -c apk add --no-cache ca-certificates tzdata # buildkit",
|
||||
"comment": "buildkit.dockerfile.v0"
|
||||
},
|
||||
{
|
||||
"created": "2026-02-05T10:39:47.416410394+01:00",
|
||||
"created_by": "RUN /bin/sh -c adduser -D -u 1000 appuser # buildkit",
|
||||
"comment": "buildkit.dockerfile.v0"
|
||||
},
|
||||
{
|
||||
"created": "2026-02-05T10:39:47.511062104+01:00",
|
||||
"created_by": "USER appuser",
|
||||
"comment": "buildkit.dockerfile.v0",
|
||||
"empty_layer": true
|
||||
},
|
||||
{
|
||||
"created": "2026-02-05T10:39:47.511062104+01:00",
|
||||
"created_by": "WORKDIR /app",
|
||||
"comment": "buildkit.dockerfile.v0"
|
||||
},
|
||||
{
|
||||
"created": "2026-02-05T10:40:02.940564676+01:00",
|
||||
"created_by": "COPY /build/contact-mailer . # buildkit",
|
||||
"comment": "buildkit.dockerfile.v0"
|
||||
},
|
||||
{
|
||||
"created": "2026-02-05T10:40:02.940564676+01:00",
|
||||
"created_by": "EXPOSE [8080/tcp]",
|
||||
"comment": "buildkit.dockerfile.v0",
|
||||
"empty_layer": true
|
||||
},
|
||||
{
|
||||
"created": "2026-02-05T10:40:02.940564676+01:00",
|
||||
"created_by": "ENTRYPOINT [\"./contact-mailer\"]",
|
||||
"comment": "buildkit.dockerfile.v0",
|
||||
"empty_layer": true
|
||||
}
|
||||
]
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
# read-only whole-disk search for the contact-mailer source. Prints only paths.
|
||||
P=( -path /proc -o -path /sys -o -path /dev -o -path /run -o -path /tmp/claude-1000 \
|
||||
-o -path /var/lib/docker -o -path /var/lib/containerd -o -path /var/lib/containerd.pre-move-2026-08-05 -o -path /var/lib/rancher \
|
||||
-o -path /var/lib/kubelet -o -path /var/lib/longhorn -o -path /var/lib/proxmox-backup -o -path /mnt/ssd_2/replicas -o -path /mnt/ssd_2/containerd \
|
||||
-o -path /mnt/backup-longhorn -o -name .chunks -o -name Download -o -name Series -o -name Movies -o -name Cartoons -o -name Kids \
|
||||
-o -name Audiobook -o -name Photos -o -name Videos -o -name "Phone Backup" -o -path /mnt/plex_media -o -name lost+found )
|
||||
echo "# name search"
|
||||
find / \( "${P[@]}" \) -prune -o \( -iname '*contact-mailer*' -o -iname '*contact_mailer*' \) -print 2>/dev/null
|
||||
echo "# content search (*.go, go.mod, Dockerfile*)"
|
||||
find / \( "${P[@]}" \) -prune -o -type f \( -name '*.go' -o -name go.mod -o -name 'Dockerfile*' \) -size -2M -print0 2>/dev/null \
|
||||
| xargs -0 grep -l -E 'sendViaResend|buildEmailHTML|felhom/contact-mailer|RESEND_API_KEY|contact-mailer|contact_mailer' 2>/dev/null
|
||||
echo "# count of files content-searched"
|
||||
find / \( "${P[@]}" \) -prune -o -type f \( -name '*.go' -o -name go.mod -o -name 'Dockerfile*' \) -size -2M -print 2>/dev/null | wc -l
|
||||
echo "# done"
|
||||
@@ -1,3 +1,9 @@
|
||||
## gates — the decoy suite runs one at a time (2026-10-08, fixed without a row)
|
||||
|
||||
- `test_gate_decoys.py` takes an exclusive `fcntl.flock` on `.git/decoy-suite.lock` before planting anything. Two runs at
|
||||
once in the shared worktree (two sessions running the gates together) had left a decoy planted for good
|
||||
(`website/en/apps.html` without its Radicale logo, local only, restored). A second run now waits for the first.
|
||||
|
||||
## gates — the language globe (site_gates.py gates 3 and 13; 2026-10-08)
|
||||
|
||||
- One language list, `LANGS = [("hu", "Magyar"), ("en", "English")]`, with `GLOBE_LABEL`. Gate 3 normalises the
|
||||
|
||||
@@ -34,6 +34,14 @@ import sys
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# ONE RUN AT A TIME (2026-10-08). The decoys mutate REAL files and restore them from a backup taken at plant time. Two
|
||||
# runs at once in the shared worktree (two sessions running the gates together) let run B back up a file run A had
|
||||
# already mutated, and B's "restore" then wrote A's decoy back for good: website/en/apps.html was left without its
|
||||
# Radicale logo, one step from a push. An exclusive lock makes a second run WAIT for the first.
|
||||
import fcntl
|
||||
_LOCK = open(os.path.join(ROOT, ".git", "decoy-suite.lock"), "w")
|
||||
fcntl.flock(_LOCK, fcntl.LOCK_EX)
|
||||
|
||||
# ── WHAT THIS FILE COVERS ────────────────────────────────────────────────────────────────────────
|
||||
# Read by scripts/decoy_coverage_gate.py, which AST-parses this literal rather than grepping for
|
||||
# gate names — a substring search for coverage would be the very shape this sweep exists to find.
|
||||
|
||||
Reference in New Issue
Block a user