Owner directive (sneak, chat, 2026-09-24 09:49 UTC, verbatim): "focus on webhooker and pixa first". It answers sneak/project-management#1. His goal is to run six apps in beta under upaas (https://git.eeqj.de/sneak/upaas) on fsn1app1, and webhooker and pixa get their readiness work first. Standing owner ruling (2026-08-30): upaas deploys each app from a prod branch cut from main, so releases stay independent of what the instances run. Setting up the app in upaas and the deploy itself are the owner's.
Most of what upaas needs is already on next (README, "Running with Docker"):
the image runs as a non-root user (UID 1000) and listens on port 8080;
every database lives under /var/lib/webhooker;
all settings come from the environment;
the health check is /.well-known/healthcheck.
This issue covers the rest.
Definition of done
A prod branch exists, cut from main as it stands. It moves forward only through reviewed main to prod PRs; nothing is pushed to it directly.
The image is built and run twice against the same data volume, mounted the way upaas mounts an app's volume. The second run starts with the first run's data: it does not print the first-boot admin banner again.
upaas's README and code show how it mounts that volume and which user owns it. The image runs as UID 1000 and does not start when it cannot take its lock in the data directory. If a fresh upaas volume would stop the container from starting, this issue removes that obstacle.
README.md gains a short "Running under upaas" section. It lists exactly what the upaas app needs:
the container port;
the volume path;
each environment variable upaas should set, with its value. At least WEBHOOKER_ENVIRONMENT, whose default #322 changes to prod. Also TRUSTED_PROXIES, if requests reach the app through a proxy. The Configuration table covers the rest.
the health check;
the first-run steps: where to read the one-time admin password banner, and webhooker resetpw admin if it is lost.
Any code change this needs lands on next through the usual reviewed PR. The open milestone PR #321 then lists it.
Use only settings upaas actually has. Read its README, and its code where the README is silent (how an app's port, volume and health check are set). Invent nothing.
Standing rulings that bound this work:
The webhook UUID in the URL is the credential: no signing, no shared secrets.
Admin login security is settled as good enough.
No agent tags 1.0. Only sneak does, after he runs webhooker in limited production.
Model: opus-5-5
Owner directive (sneak, chat, 2026-09-24 09:49 UTC, verbatim): "focus on webhooker and pixa first". It answers https://git.eeqj.de/sneak/project-management/issues/1. His goal is to run six apps in beta under upaas (https://git.eeqj.de/sneak/upaas) on fsn1app1, and webhooker and pixa get their readiness work first. Standing owner ruling (2026-08-30): upaas deploys each app from a `prod` branch cut from `main`, so releases stay independent of what the instances run. Setting up the app in upaas and the deploy itself are the owner's.
Most of what upaas needs is already on `next` (README, "Running with Docker"):
- the image runs as a non-root user (UID 1000) and listens on port 8080;
- every database lives under `/var/lib/webhooker`;
- all settings come from the environment;
- the health check is `/.well-known/healthcheck`.
This issue covers the rest.
## Definition of done
- A `prod` branch exists, cut from `main` as it stands. It moves forward only through reviewed `main` to `prod` PRs; nothing is pushed to it directly.
- The image is built and run twice against the same data volume, mounted the way upaas mounts an app's volume. The second run starts with the first run's data: it does not print the first-boot admin banner again.
- upaas's README and code show how it mounts that volume and which user owns it. The image runs as UID 1000 and does not start when it cannot take its lock in the data directory. If a fresh upaas volume would stop the container from starting, this issue removes that obstacle.
- `README.md` gains a short "Running under upaas" section. It lists exactly what the upaas app needs:
- the container port;
- the volume path;
- each environment variable upaas should set, with its value. At least `WEBHOOKER_ENVIRONMENT`, whose default https://git.eeqj.de/sneak/webhooker/pulls/322 changes to `prod`. Also `TRUSTED_PROXIES`, if requests reach the app through a proxy. The Configuration table covers the rest.
- the health check;
- the first-run steps: where to read the one-time admin password banner, and `webhooker resetpw admin` if it is lost.
- Any code change this needs lands on `next` through the usual reviewed PR. The open milestone PR https://git.eeqj.de/sneak/webhooker/pulls/321 then lists it.
Use only settings upaas actually has. Read its README, and its code where the README is silent (how an app's port, volume and health check are set). Invent nothing.
Standing rulings that bound this work:
- The webhook UUID in the URL is the credential: no signing, no shared secrets.
- Admin login security is settled as good enough.
- No agent tags 1.0. Only sneak does, after he runs webhooker in limited production.
Model: opus-5-5
clawbot
self-assigned this 2026-09-24 17:58:59 +02:00
Plan for the webhooker repo-manager, launched when a worker account next has room (27 September 23:00 UTC at the earliest). sneak's ruling of 24 September puts webhooker first for the beta on fsn1app1, with pixa (sneak/project-management#1).
Scope, in this order:
This issue; its definition of done is the work.
The open queue, both PRs to next: #322 (default WEBHOOKER_ENVIRONMENT to prod) needs its independent review; #319 (event-tier indexes) needs rework against its review findings. Land 322 before this issue's README section, so the section can state the new default; if 322 stalls, the section states the value upaas should set.
When this issue, 322 and 319 are on next and next is green, update the milestone PR #321 (next into main): its description lists everything on the branch; label it merge-ready and assign it to sneak. It stays open until he merges; units keep landing on next meanwhile, and its description is updated after each merge.
The other open issues (the list in #311) stay parked unless one blocks this issue.
sneak's standing rulings for webhooker, never reopened:
The webhook UUID in the URL is the credential. Never propose signing, HMAC, bearer tokens or shared secrets, including for defence in depth.
Admin login security is good enough. Never file or re-flag login rate-limit header spoofing, argon2 login cost, session revocation on password change, stolen-cookie lifetime or login timing.
No agent tags 1.0 or suggests the tag; only sneak lifts that gate, after he runs webhooker in limited production.
prod is cut once from main (this issue); after that it moves only through reviewed main to prod PRs.
Model: opus-5-5
Plan for the webhooker repo-manager, launched when a worker account next has room (27 September 23:00 UTC at the earliest). sneak's ruling of 24 September puts webhooker first for the beta on fsn1app1, with pixa (https://git.eeqj.de/sneak/project-management/issues/1).
Scope, in this order:
- This issue; its definition of done is the work.
- The open queue, both PRs to `next`: https://git.eeqj.de/sneak/webhooker/pulls/322 (default `WEBHOOKER_ENVIRONMENT` to `prod`) needs its independent review; https://git.eeqj.de/sneak/webhooker/pulls/319 (event-tier indexes) needs rework against its review findings. Land 322 before this issue's README section, so the section can state the new default; if 322 stalls, the section states the value upaas should set.
- When this issue, 322 and 319 are on `next` and `next` is green, update the milestone PR https://git.eeqj.de/sneak/webhooker/pulls/321 (`next` into `main`): its description lists everything on the branch; label it merge-ready and assign it to sneak. It stays open until he merges; units keep landing on `next` meanwhile, and its description is updated after each merge.
The other open issues (the list in https://git.eeqj.de/sneak/webhooker/issues/311) stay parked unless one blocks this issue.
sneak's standing rulings for webhooker, never reopened:
- The webhook UUID in the URL is the credential. Never propose signing, HMAC, bearer tokens or shared secrets, including for defence in depth.
- Admin login security is good enough. Never file or re-flag login rate-limit header spoofing, argon2 login cost, session revocation on password change, stolen-cookie lifetime or login timing.
- No agent tags 1.0 or suggests the tag; only sneak lifts that gate, after he runs webhooker in limited production.
- `prod` is cut once from `main` (this issue); after that it moves only through reviewed `main` to `prod` PRs.
Model: opus-5-5
Implementer's brief. prod is cut from main at 251cb3d; that part of the definition of done is done and nothing else touches prod.
What upaas does (its main, 6026e39), from its README and code:
Volume: a Docker bind mount of an absolute host path onto a container path, both typed into the app's settings (internal/docker/client.go, buildMounts, mount type bind). upaas never creates the host directory, and Docker refuses a bind mount whose source does not exist, so the operator creates it before the first deploy. upaas has no setting for the container user; the image's USER stands.
Port: per-app mappings of a host port to a container port.
Health check: the image's own HEALTHCHECK. 60 seconds after a deploy upaas inspects the container and fails the deploy unless it is healthy (internal/service/deploy/deploy.go, checkHealthAfterDelay; internal/docker/client.go, IsContainerHealthy).
Environment: per-app environment variables. upaas runs no reverse proxy; TLS and the proxy in front of the app are the owner's.
The obstacle: a host directory made with a plain mkdir as root is root:root 0755. The container runs as UID 1000, cannot create webhooker.lock, exits, and upaas restarts it forever.
Decision: remove it in the README, not the image. The section's first-run steps create the directory owned by UID 1000 before the first deploy (mkdir, chown 1000:1000, chmod 750), as homoicon's upaas section does for its volume. The image keeps running as UID 1000 and keeps refusing to start without its lock. No code change is expected. If the checks below show the image cannot start on a UID-1000-owned bind mount, stop and report it here.
Checks (verify, publish none of the evidence): build with make docker, then run with docker run --mount type=bind,source=DIR,target=/var/lib/webhooker, the mount type upaas uses.
A missing source directory: Docker refuses to start.
A root-owned directory (make it through a throwaway root container; the host user is UID 1000): the container exits with the lock error.
A UID-1000-owned directory: the first run prints the admin banner and is healthy within 60 seconds. Stop and remove it, run a new container on the same directory: no banner, and the first run's password still logs in.
The resetpw command the section gives works against that directory with the app stopped.
The README section "Running under upaas", next to "Running with Docker", short:
container port 8080, and leave PORT unset, because the image's health check probes 8080;
the volume: one host directory at /var/lib/webhooker, with the commands that create it;
environment: WEBHOOKER_ENVIRONMENT=prod, and if #322 is on next when you rebase, say prod is also the default; TRUSTED_PROXIES set to the address the proxy connects from as the container sees it, linking the Trusted proxies section; leave BIND_ADDRESS and DATA_DIR unset, since the image sets both; everything else per the Configuration table;
the health check, /.well-known/healthcheck, read by upaas 60 seconds after a deploy;
first run: the banner is in the container's log; if the password is lost, webhooker resetpw admin with the app stopped, as a command that works.
State only what upaas's README or code shows; invent no upaas setting.
Model: opus-5-5
Implementer's brief. `prod` is cut from `main` at `251cb3d`; that part of the definition of done is done and nothing else touches `prod`.
What upaas does (its `main`, `6026e39`), from its README and code:
- **Volume**: a Docker bind mount of an absolute host path onto a container path, both typed into the app's settings (`internal/docker/client.go`, `buildMounts`, mount type `bind`). upaas never creates the host directory, and Docker refuses a bind mount whose source does not exist, so the operator creates it before the first deploy. upaas has no setting for the container user; the image's `USER` stands.
- **Port**: per-app mappings of a host port to a container port.
- **Health check**: the image's own `HEALTHCHECK`. 60 seconds after a deploy upaas inspects the container and fails the deploy unless it is `healthy` (`internal/service/deploy/deploy.go`, `checkHealthAfterDelay`; `internal/docker/client.go`, `IsContainerHealthy`).
- **Environment**: per-app environment variables. upaas runs no reverse proxy; TLS and the proxy in front of the app are the owner's.
The obstacle: a host directory made with a plain `mkdir` as root is `root:root 0755`. The container runs as UID 1000, cannot create `webhooker.lock`, exits, and upaas restarts it forever.
Decision: remove it in the README, not the image. The section's first-run steps create the directory owned by UID 1000 before the first deploy (`mkdir`, `chown 1000:1000`, `chmod 750`), as homoicon's upaas section does for its volume. The image keeps running as UID 1000 and keeps refusing to start without its lock. No code change is expected. If the checks below show the image cannot start on a UID-1000-owned bind mount, stop and report it here.
Checks (verify, publish none of the evidence): build with `make docker`, then run with `docker run --mount type=bind,source=DIR,target=/var/lib/webhooker`, the mount type upaas uses.
1. A missing source directory: Docker refuses to start.
2. A root-owned directory (make it through a throwaway root container; the host user is UID 1000): the container exits with the lock error.
3. A UID-1000-owned directory: the first run prints the admin banner and is `healthy` within 60 seconds. Stop and remove it, run a new container on the same directory: no banner, and the first run's password still logs in.
4. The `resetpw` command the section gives works against that directory with the app stopped.
The README section "Running under upaas", next to "Running with Docker", short:
- container port `8080`, and leave `PORT` unset, because the image's health check probes 8080;
- the volume: one host directory at `/var/lib/webhooker`, with the commands that create it;
- environment: `WEBHOOKER_ENVIRONMENT=prod`, and if https://git.eeqj.de/sneak/webhooker/pulls/322 is on `next` when you rebase, say `prod` is also the default; `TRUSTED_PROXIES` set to the address the proxy connects from as the container sees it, linking the Trusted proxies section; leave `BIND_ADDRESS` and `DATA_DIR` unset, since the image sets both; everything else per the Configuration table;
- the health check, `/.well-known/healthcheck`, read by upaas 60 seconds after a deploy;
- first run: the banner is in the container's log; if the password is lost, `webhooker resetpw admin` with the app stopped, as a command that works.
State only what upaas's README or code shows; invent no upaas setting.
Model: opus-5-5
Opened #324: a "Running under upaas" section in the README, covering the port, the volume and how to create it, the environment variables, the health check, and the first-run steps. The image is unchanged.
Model: opus-5-5
Opened https://git.eeqj.de/sneak/webhooker/pulls/324: a "Running under upaas" section in the README, covering the port, the volume and how to create it, the environment variables, the health check, and the first-run steps. The image is unchanged.
Model: opus-5-5
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.
Owner directive (sneak, chat, 2026-09-24 09:49 UTC, verbatim): "focus on webhooker and pixa first". It answers sneak/project-management#1. His goal is to run six apps in beta under upaas (https://git.eeqj.de/sneak/upaas) on fsn1app1, and webhooker and pixa get their readiness work first. Standing owner ruling (2026-08-30): upaas deploys each app from a
prodbranch cut frommain, so releases stay independent of what the instances run. Setting up the app in upaas and the deploy itself are the owner's.Most of what upaas needs is already on
next(README, "Running with Docker"):/var/lib/webhooker;/.well-known/healthcheck.This issue covers the rest.
Definition of done
prodbranch exists, cut frommainas it stands. It moves forward only through reviewedmaintoprodPRs; nothing is pushed to it directly.README.mdgains a short "Running under upaas" section. It lists exactly what the upaas app needs:WEBHOOKER_ENVIRONMENT, whose default #322 changes toprod. AlsoTRUSTED_PROXIES, if requests reach the app through a proxy. The Configuration table covers the rest.webhooker resetpw adminif it is lost.nextthrough the usual reviewed PR. The open milestone PR #321 then lists it.Use only settings upaas actually has. Read its README, and its code where the README is silent (how an app's port, volume and health check are set). Invent nothing.
Standing rulings that bound this work:
Model: opus-5-5
Plan for the webhooker repo-manager, launched when a worker account next has room (27 September 23:00 UTC at the earliest). sneak's ruling of 24 September puts webhooker first for the beta on fsn1app1, with pixa (sneak/project-management#1).
Scope, in this order:
next: #322 (defaultWEBHOOKER_ENVIRONMENTtoprod) needs its independent review; #319 (event-tier indexes) needs rework against its review findings. Land 322 before this issue's README section, so the section can state the new default; if 322 stalls, the section states the value upaas should set.nextandnextis green, update the milestone PR #321 (nextintomain): its description lists everything on the branch; label it merge-ready and assign it to sneak. It stays open until he merges; units keep landing onnextmeanwhile, and its description is updated after each merge.The other open issues (the list in #311) stay parked unless one blocks this issue.
sneak's standing rulings for webhooker, never reopened:
prodis cut once frommain(this issue); after that it moves only through reviewedmaintoprodPRs.Model: opus-5-5
Implementer's brief.
prodis cut frommainat251cb3d; that part of the definition of done is done and nothing else touchesprod.What upaas does (its
main,6026e39), from its README and code:internal/docker/client.go,buildMounts, mount typebind). upaas never creates the host directory, and Docker refuses a bind mount whose source does not exist, so the operator creates it before the first deploy. upaas has no setting for the container user; the image'sUSERstands.HEALTHCHECK. 60 seconds after a deploy upaas inspects the container and fails the deploy unless it ishealthy(internal/service/deploy/deploy.go,checkHealthAfterDelay;internal/docker/client.go,IsContainerHealthy).The obstacle: a host directory made with a plain
mkdiras root isroot:root 0755. The container runs as UID 1000, cannot createwebhooker.lock, exits, and upaas restarts it forever.Decision: remove it in the README, not the image. The section's first-run steps create the directory owned by UID 1000 before the first deploy (
mkdir,chown 1000:1000,chmod 750), as homoicon's upaas section does for its volume. The image keeps running as UID 1000 and keeps refusing to start without its lock. No code change is expected. If the checks below show the image cannot start on a UID-1000-owned bind mount, stop and report it here.Checks (verify, publish none of the evidence): build with
make docker, then run withdocker run --mount type=bind,source=DIR,target=/var/lib/webhooker, the mount type upaas uses.healthywithin 60 seconds. Stop and remove it, run a new container on the same directory: no banner, and the first run's password still logs in.resetpwcommand the section gives works against that directory with the app stopped.The README section "Running under upaas", next to "Running with Docker", short:
8080, and leavePORTunset, because the image's health check probes 8080;/var/lib/webhooker, with the commands that create it;WEBHOOKER_ENVIRONMENT=prod, and if #322 is onnextwhen you rebase, sayprodis also the default;TRUSTED_PROXIESset to the address the proxy connects from as the container sees it, linking the Trusted proxies section; leaveBIND_ADDRESSandDATA_DIRunset, since the image sets both; everything else per the Configuration table;/.well-known/healthcheck, read by upaas 60 seconds after a deploy;webhooker resetpw adminwith the app stopped, as a command that works.State only what upaas's README or code shows; invent no upaas setting.
Model: opus-5-5
Opened #324: a "Running under upaas" section in the README, covering the port, the volume and how to create it, the environment variables, the health check, and the first-run steps. The image is unchanged.
Model: opus-5-5