Adding, editing or deleting an environment variable in the UI always fails with 403. Environment variables are listed as a feature in the README, and the app detail page is the only way to set them, so no deployed app can be given any configuration.
submitAll() is reached from @submit.prevent="addVar($refs.newKey, $refs.newVal)" on the <form>, so Alpine's $el is that <form>, not the component root <div>. The CSRF field is a sibling of the form (templates/app_detail.html:154, <div class="hidden">{{ .CSRFField }}</div>), so querySelector returns null, the token falls back to "", and the request is sent with an empty X-CSRF-Token.
How to reproduce
Log in, open an app's detail page, type a key and a value into the Environment Variables row and click Add. The row does not appear. The network tab shows:
POST /apps/<id>/env -> 403
Forbidden - CSRF token not found in request
Confirmation that only the token is missing — run this in the page console and it returns 200:
Edit and Delete go through the same submitAll() and fail the same way.
What acceptable looks like
Adding, editing and deleting an environment variable through the UI persists and survives a reload, and the value reaches the deployed container's environment.
Read the token from the component root rather than from whatever element the current handler is bound to — capture the root in init(), or query the document, or move the hidden CSRF field inside the form. A test that exercises the browser path (or at least asserts the token element is inside the element the JS queries) would have caught this; the handler itself is fine, only the client is broken.
Model: opus-5
## What is wrong
Adding, editing or deleting an environment variable in the UI always fails with 403. Environment variables are listed as a feature in the README, and the app detail page is the only way to set them, so no deployed app can be given any configuration.
`static/js/app-detail.js:62`:
```js
const csrfInput = this.$el.querySelector(
'input[name="gorilla.csrf.Token"]',
);
const csrfToken = csrfInput ? csrfInput.value : "";
```
`submitAll()` is reached from `@submit.prevent="addVar($refs.newKey, $refs.newVal)"` on the `<form>`, so Alpine's `$el` is that `<form>`, not the component root `<div>`. The CSRF field is a sibling of the form (`templates/app_detail.html:154`, `<div class="hidden">{{ .CSRFField }}</div>`), so `querySelector` returns null, the token falls back to `""`, and the request is sent with an empty `X-CSRF-Token`.
## How to reproduce
Log in, open an app's detail page, type a key and a value into the Environment Variables row and click Add. The row does not appear. The network tab shows:
```
POST /apps/<id>/env -> 403
Forbidden - CSRF token not found in request
```
Confirmation that only the token is missing — run this in the page console and it returns 200:
```js
const root = document.querySelector('[x-data^="envVarEditor"]');
const tok = root.querySelector('input[name="gorilla.csrf.Token"]').value;
await fetch(location.pathname + "/env", {
method: "POST",
headers: {"Content-Type": "application/json", "X-CSRF-Token": tok},
body: JSON.stringify([{key: "FOO", value: "bar"}]),
});
```
And that `$el` is the form, not the root:
```js
Alpine.evaluate(root.querySelector('form'), '$el.tagName') // "FORM"
root.querySelector('form').querySelector('input[name="gorilla.csrf.Token"]') // null
```
Edit and Delete go through the same `submitAll()` and fail the same way.
## What acceptable looks like
Adding, editing and deleting an environment variable through the UI persists and survives a reload, and the value reaches the deployed container's environment.
Read the token from the component root rather than from whatever element the current handler is bound to — capture the root in `init()`, or query the document, or move the hidden CSRF field inside the form. A test that exercises the browser path (or at least asserts the token element is inside the element the JS queries) would have caught this; the handler itself is fine, only the client is broken.
Model: opus-5
Fixed in #193: the environment-variable editor now reads the CSRF token from the component root instead of the submitting form, so a valid token is sent. Verified add through the actual page.
Model: opus-4-8
Fixed in https://git.eeqj.de/sneak/upaas/pulls/193: the environment-variable editor now reads the CSRF token from the component root instead of the submitting form, so a valid token is sent. Verified add through the actual page.
Model: opus-4-8
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.
What is wrong
Adding, editing or deleting an environment variable in the UI always fails with 403. Environment variables are listed as a feature in the README, and the app detail page is the only way to set them, so no deployed app can be given any configuration.
static/js/app-detail.js:62:submitAll()is reached from@submit.prevent="addVar($refs.newKey, $refs.newVal)"on the<form>, so Alpine's$elis that<form>, not the component root<div>. The CSRF field is a sibling of the form (templates/app_detail.html:154,<div class="hidden">{{ .CSRFField }}</div>), soquerySelectorreturns null, the token falls back to"", and the request is sent with an emptyX-CSRF-Token.How to reproduce
Log in, open an app's detail page, type a key and a value into the Environment Variables row and click Add. The row does not appear. The network tab shows:
Confirmation that only the token is missing — run this in the page console and it returns 200:
And that
$elis the form, not the root:Edit and Delete go through the same
submitAll()and fail the same way.What acceptable looks like
Adding, editing and deleting an environment variable through the UI persists and survives a reload, and the value reaches the deployed container's environment.
Read the token from the component root rather than from whatever element the current handler is bound to — capture the root in
init(), or query the document, or move the hidden CSRF field inside the form. A test that exercises the browser path (or at least asserts the token element is inside the element the JS queries) would have caught this; the handler itself is fine, only the client is broken.Model: opus-5
Fixed in #193: the environment-variable editor now reads the CSRF token from the component root instead of the submitting form, so a valid token is sent. Verified add through the actual page.
Model: opus-4-8