Closes#189, #190, #191, #192. Grouped because each is a small, independent fix in a different file, verified together by one end-to-end run.
#189 — CSRF over plain HTTP. gorilla/csrf assumes an https scheme for its same-origin check, so setup and every POST returned 403 over plain HTTP; csrf.Secure(false) only clears the cookie flag. New UPAAS_PLAINTEXT_HTTP config gates csrf.PlaintextHTTPRequest. Default is off (https assumed), correct behind a TLS-terminating reverse proxy — the production case — so CSRF is not weakened there. The README plain-HTTP docker run recipe now sets the flag. Decision: gated, not always-on, because always-on would break origin checks under real TLS.
#190 — git image never pulled.ensureImage inspects alpine/git (pinned digest unchanged) and pulls it when absent, before the clone container is created.
#192 — port-mapping 500. The ports delete form used {{ .CSRFField }} inside {{range .Ports}}; changed to {{ $.CSRFField }}. Checked the whole template — this was the only .CSRFField left inside a range.
#191 — env-var 403. The editor read the token from $el (the submitting form, which has no token input) instead of $root; it now sends the real token.
Verification: built with make docker (the Dockerfile runs the checks), ran the container over plain HTTP, and drove each flow — admin setup, add-port then reload, env-var add through the real Alpine JS (headless Chromium), and a webhook deploy of clawbot/go-template-repo with a temporary deploy key (removed after) that pulled the git image and cloned successfully. Added a CSRF middleware test.
Model: opus-4-8
Closes #189, #190, #191, #192. Grouped because each is a small, independent fix in a different file, verified together by one end-to-end run.
**#189 — CSRF over plain HTTP.** gorilla/csrf assumes an https scheme for its same-origin check, so setup and every POST returned 403 over plain HTTP; `csrf.Secure(false)` only clears the cookie flag. New `UPAAS_PLAINTEXT_HTTP` config gates `csrf.PlaintextHTTPRequest`. Default is off (https assumed), correct behind a TLS-terminating reverse proxy — the production case — so CSRF is not weakened there. The README plain-HTTP `docker run` recipe now sets the flag. Decision: gated, not always-on, because always-on would break origin checks under real TLS.
**#190 — git image never pulled.** `ensureImage` inspects `alpine/git` (pinned digest unchanged) and pulls it when absent, before the clone container is created.
**#192 — port-mapping 500.** The ports delete form used `{{ .CSRFField }}` inside `{{range .Ports}}`; changed to `{{ $.CSRFField }}`. Checked the whole template — this was the only `.CSRFField` left inside a range.
**#191 — env-var 403.** The editor read the token from `$el` (the submitting form, which has no token input) instead of `$root`; it now sends the real token.
Verification: built with `make docker` (the Dockerfile runs the checks), ran the container over plain HTTP, and drove each flow — admin setup, add-port then reload, env-var add through the real Alpine JS (headless Chromium), and a webhook deploy of `clawbot/go-template-repo` with a temporary deploy key (removed after) that pulled the git image and cloned successfully. Added a CSRF middleware test.
Model: opus-4-8
- CSRF over plain HTTP (#189): gorilla/csrf assumed https for its
same-origin check, so setup and every POST returned 403 over plain
HTTP. Gate csrf.PlaintextHTTPRequest on a new UPAAS_PLAINTEXT_HTTP
config value; the default keeps https, correct for a TLS-terminating
reverse proxy. The README plain-HTTP recipe now sets it.
- git image never pulled (#190): ensureImage pulls alpine/git (pinned
digest unchanged) when absent, before the clone container is created.
- port-mapping 500 (#192): the ports delete form used {{ .CSRFField }}
inside {{range .Ports}}, where the dot is a *models.Port; use
{{ $.CSRFField }} like the labels and volumes blocks.
- env-var 403 (#191): the editor read the CSRF token from $el (the
submitting form, which has none) instead of $root, sending an empty
token; read from $root.
Model: opus-4-8
clawbot
self-assigned this 2026-09-09 16:13:07 +02:00
PASS — built the image via script/cibuild (forced-fresh check stages) and ran the container over plain HTTP per the README recipe, confirming all four flows end to end: admin setup succeeds over plain HTTP with UPAAS_PLAINTEXT_HTTP=true (#189), a webhook deploy of clawbot/go-template-repo pulled the absent pinned alpine/git image and cloned successfully (#190), an environment variable added through the UI saved without a 403 (#191), and after adding a port mapping the app detail page reloads with HTTP 200 instead of 500 (#192).
Model: opus-4-8
PASS — built the image via `script/cibuild` (forced-fresh check stages) and ran the container over plain HTTP per the README recipe, confirming all four flows end to end: admin setup succeeds over plain HTTP with `UPAAS_PLAINTEXT_HTTP=true` (#189), a webhook deploy of `clawbot/go-template-repo` pulled the absent pinned `alpine/git` image and cloned successfully (#190), an environment variable added through the UI saved without a 403 (#191), and after adding a port mapping the app detail page reloads with HTTP 200 instead of 500 (#192).
Model: opus-4-8
Automated squash-merge as clawbot was refused by branch protection (HTTP 405, user not allowed to merge). Labeled merge-ready; needs @sneak to squash-merge into main.
Model: opus-4-8
Automated squash-merge as clawbot was refused by branch protection (HTTP 405, user not allowed to merge). Labeled merge-ready; needs @sneak to squash-merge into main.
Model: opus-4-8
sneak
merged commit 8597b70954 into main2026-09-10 11:17:41 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #189, #190, #191, #192. Grouped because each is a small, independent fix in a different file, verified together by one end-to-end run.
#189 — CSRF over plain HTTP. gorilla/csrf assumes an https scheme for its same-origin check, so setup and every POST returned 403 over plain HTTP;
csrf.Secure(false)only clears the cookie flag. NewUPAAS_PLAINTEXT_HTTPconfig gatescsrf.PlaintextHTTPRequest. Default is off (https assumed), correct behind a TLS-terminating reverse proxy — the production case — so CSRF is not weakened there. The README plain-HTTPdocker runrecipe now sets the flag. Decision: gated, not always-on, because always-on would break origin checks under real TLS.#190 — git image never pulled.
ensureImageinspectsalpine/git(pinned digest unchanged) and pulls it when absent, before the clone container is created.#192 — port-mapping 500. The ports delete form used
{{ .CSRFField }}inside{{range .Ports}}; changed to{{ $.CSRFField }}. Checked the whole template — this was the only.CSRFFieldleft inside a range.#191 — env-var 403. The editor read the token from
$el(the submitting form, which has no token input) instead of$root; it now sends the real token.Verification: built with
make docker(the Dockerfile runs the checks), ran the container over plain HTTP, and drove each flow — admin setup, add-port then reload, env-var add through the real Alpine JS (headless Chromium), and a webhook deploy ofclawbot/go-template-repowith a temporary deploy key (removed after) that pulled the git image and cloned successfully. Added a CSRF middleware test.Model: opus-4-8
PASS — built the image via
script/cibuild(forced-fresh check stages) and ran the container over plain HTTP per the README recipe, confirming all four flows end to end: admin setup succeeds over plain HTTP withUPAAS_PLAINTEXT_HTTP=true(#189), a webhook deploy ofclawbot/go-template-repopulled the absent pinnedalpine/gitimage and cloned successfully (#190), an environment variable added through the UI saved without a 403 (#191), and after adding a port mapping the app detail page reloads with HTTP 200 instead of 500 (#192).Model: opus-4-8
Automated squash-merge as clawbot was refused by branch protection (HTTP 405, user not allowed to merge). Labeled merge-ready; needs @sneak to squash-merge into main.
Model: opus-4-8