Commit Graph

14 Commits

Author SHA1 Message Date
dependabot[bot] 019c335a87 chore(docker)(deps): bump golang in the docker-minor-and-patch group (#1188)
Bumps the docker-minor-and-patch group with 1 update: golang.


Updates `golang` from 1.26-alpine to 1.27-alpine

---
updated-dependencies:
- dependency-name: golang
  dependency-version: 1.27-alpine
  dependency-type: direct:production
  dependency-group: docker-minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-24 11:09:33 -04:00
dependabot[bot] e8e1822bfc chore(docker)(deps): bump node from 24-alpine to 26-alpine (#497)
Bumps node from 24-alpine to 26-alpine.

---
updated-dependencies:
- dependency-name: node
  dependency-version: 26-alpine
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-11 01:36:16 -04:00
dependabot[bot] d26d649cb5 chore(docker)(deps): bump alpine (#728)
Bumps the docker-minor-and-patch group with 1 update in the / directory: alpine.


Updates `alpine` from 3.23 to 3.24

---
updated-dependencies:
- dependency-name: alpine
  dependency-version: '3.24'
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: docker-minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-11 01:36:11 -04:00
xarmian e380b4e660 chore(deps): bump Node 22 → 24 (Dockerfile + CI workflows) (TASK-1235) (#443)
Bumps all four Node version pins from "22" to "24" together so CI ↔
production stay aligned:
  • Dockerfile (production image): node:22-alpine → node:24-alpine
  • .github/workflows/ci.yml — Web job + E2E job
  • .github/workflows/release.yml — release pipeline

Going to LTS-bound 24 instead of dependabot's proposed 25-alpine,
which hits EOL on 2026-06-01 (~3 weeks from this commit). Going to
24 instead of waiting for 26-LTS (Oct 2026) because 5 months is too
long to sit on the deferred-bumps backlog and 24 is already a year
into LTS-tested production use. Worst case follow-up is one more
trivial Dockerfile bump in October.

Verified:
  • Local `docker build --target web-builder` on node:24-alpine
    (npm ci + npm run build) — clean, 24s end-to-end
  • `make check` — golangci-lint + go test + npm run build +
    svelte-check, 0 errors

Closes dependabot/docker/node-25-alpine (PR #209) — closing rather
than rebasing because we're going to 24, not 25.
2026-05-08 07:32:43 -04:00
dependabot[bot] 1c86165b77 chore(docker)(deps): bump alpine (#248)
Bumps the docker-minor-and-patch group with 1 update in the / directory: alpine.


Updates `alpine` from 3.21 to 3.23

---
updated-dependencies:
- dependency-name: alpine
  dependency-version: '3.23'
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: docker-minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-07 23:45:40 -04:00
xarmian 92a4931f44 feat(docker): PUID/PGID entrypoint shim for Unraid + LinuxServer-style hosts (TASK-1168) (#425)
Tiny /bin/sh entrypoint shim that, if invoked as root, reads PUID/PGID
env vars (defaulting to 99/100 — Unraid's nobody:users), remaps the
in-image pad user, chowns /data, and execs the binary via su-exec.
If invoked as non-root (caller passed --user), it just execs directly
— caller knows what they want.

Solves the classic Unraid appdata-ownership-mismatch first-run failure
where the in-image pad user (uid 1000) couldn't write to a host volume
owned by nobody:users (uid 99, gid 100). Reusable on Synology / QNAP /
TrueNAS where the host's appdata user is similarly non-1000.

Behavior changes:
- Container starts as root (USER directive removed). Entrypoint drops
  privileges via su-exec before exec'ing pad — standard PUID/PGID
  pattern. Healthcheck adapts: root → su-exec to pad; non-root →
  direct wget.
- chown -R is always-run (warn-and-continue on per-file failures). A
  shallow stat-only check would silently break pad on a restored
  backup with mixed-ownership inner files.
- Healthcheck start-period bumped 10s → 60s to absorb slow chown -R
  on large attachment stores.
- Compose default 1000/1000 for backward compat with existing deploys
  whose volumes were created under the previous USER pad image.
- Raw `docker run` defaults to 99/100 (Unraid convention).

Validation rejects PUID=0 / PGID=0 (would defeat the unprivileged-user
invariant), empty values, and non-numeric values with clear errors.

Goes through 11 rounds of codex pre-implementation design review,
catching:
- gid bug where groupmod alone leaves /etc/passwd's primary-gid stale
- compose $-interpolation gotcha (needs $$( ) not $())
- getent missing from default alpine BusyBox
- shell ${VAR:-} silently masking explicit empty values
- healthcheck running as root after USER drop
- su-exec failing for --user non-root pass-through

Part of PLAN-1166 (Pad on Unraid — Community Apps launch). Unblocks
TASK-1169 (XML template authoring).
2026-05-06 08:40:33 -04:00
xarmian 7bb9076ac5 fix(dockerfile): pass version metadata via build args instead of broken in-container substitution (TASK-1080) (#385)
The previous build line had:

    -X main.commit=$(git rev-parse --short HEAD 2>/dev/null) \
    -X main.buildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)

The `git rev-parse` ran INSIDE the build container, but .dockerignore
intentionally excludes `.git/` so the working directory has no git
metadata; the `2>/dev/null` swallowed the resulting error and the
substitution silently produced an empty string. Net result: every
Docker build of pad shipped a binary with `commit=""`, which
fullVersion() collapses to just `version` ("dev") with no commit
metadata at all. Caught during Claude Desktop dogfooding when
`pad_meta` returned `pad_version: "dev"` and bug reports had no way
to identify which build they were hitting.

Two ways to fix: add .git/ to the build context (rejected — operator
explicitly does not want .git in the image build), or pre-compute on
the host and pass via --build-arg (this PR). The wrapper that does
the host-side computation lands in pad-cloud separately.

The `date` substitution worked because alpine has `date` in the
builder image, but it had a worse problem: a fresh `date` value on
every build invalidates layer caching for this RUN. Moving to ARG
lets the caller decide cache semantics — production wrappers will
pass a real timestamp; dev rebuilds can omit BUILD_TIME entirely
to keep the cache warm.

Defaults are deliberately ugly-but-honest so a `docker build .`
without args produces "dev (unknown)" rather than hiding the
misconfiguration. Production builds with all three args produce
e.g. "0.1.0-rc.5 (40f636e 2026-05-03T00:15:00Z)".

Sanity-checked all four input combinations (defaults, all-set,
version+commit only, commit-empty) against the existing
fullVersion() logic — output shapes are clean for each.
2026-05-02 20:29:02 -04:00
xarmian 157ca4e88f chore: bump Go toolchain to 1.26 (TASK-763) (#247)
* chore: bump Go toolchain to 1.26 (TASK-763)

Bump Go from 1.25 to 1.26 across all toolchain pins:

- go.mod — go 1.25.0 → go 1.26.0
- Dockerfile — golang:1.25-alpine → golang:1.26-alpine
- .github/workflows/ci.yml — three setup-go steps (Go, Go-Postgres, E2E jobs)
- .github/workflows/release.yml — release pipeline

No `toolchain` directive: the repo is pre-launch with no external
contributors yet, so we set the floor where we want it (hard requirement).

Verified locally before commit:
- golangci-lint v2.11.4 builds and runs under Go 1.26.2 (pinned in CI)
- golang:1.26-alpine and 1.26.2-alpine images present on Docker Hub
- go build ./... clean
- go vet ./... clean
- go test ./... all pass

Parent: PLAN-644 (OSS Repo Hygiene and Launch Polish).

* chore: gofmt -w under Go 1.26 (TASK-763)

Apply Go 1.26's gofmt to the codebase. ~41 files reformatted, all
struct-tag whitespace realignment — no semantic changes. Verified:

- gofmt -l ./cmd ./internal returns empty after
- go build ./... still clean
- go test ./... still passes (run before commit)

Bundling the gofmt diff with the toolchain bump in the same PR because
the formatting drift is a direct consequence of moving from 1.25 to
1.26; splitting them creates a mandatory two-PR ordering for no value.

Parent: PLAN-644.

* docs: bump documented Go floor to 1.26 (TASK-763)

Match go.mod's hard 1.26.0 requirement in the source-build instructions.
Caught by Codex review round 1 on PR #247.

- README.md:158 — "Go 1.25+" → "Go 1.26+"
- CONTRIBUTING.md:9 — "Go 1.25+" → "Go 1.26+"
2026-04-25 11:35:19 -04:00
xarmian be9a96ba21 chore: run containers as non-root + harden K8s securityContext (TASK-680) (#219)
First thing external reviewers flag on a public repo: "why does this
image run as root?". Fixes both Dockerfiles and the K8s deployment.

Dockerfiles (Dockerfile + Dockerfile.goreleaser):
- Add a non-login uid:1000 "pad" user via adduser
- chown /data so the app can write its SQLite DB as the unprivileged user
- Declare USER pad before the ENTRYPOINT

deploy/k8s/deployment.yaml:
- Pod-level securityContext: runAsNonRoot, runAsUser/Group 1000, fsGroup
  1000 (so the emptyDir volume is group-writable), seccompProfile
  RuntimeDefault
- Container-level securityContext: allowPrivilegeEscalation false,
  readOnlyRootFilesystem true, drop ALL capabilities

Verified:
- docker build succeeds; `docker inspect ... Config.User` = "pad"
- Container running as uid 1000 serves /api/v1/health successfully
- Container runs with --read-only rootfs + writable /data volume with no
  runtime errors (server only writes to /data, never /tmp)
- deploy/k8s/deployment.yaml parses via yq; securityContext block
  structurally correct

Parent: PLAN-644.
2026-04-22 20:23:14 -04:00
xarmian 2b413f5d95 chore: add HEALTHCHECK to both Dockerfiles (TASK-681) (#218)
Before: neither Dockerfile declared HEALTHCHECK. docker-compose.yml
added it at compose level, so "docker run ghcr.io/xarmian/pad:latest"
had no health signal for Docker/Kubernetes/Swarm.

Adds HEALTHCHECK to Dockerfile and Dockerfile.goreleaser probing
GET /api/v1/health (served by internal/server/server.go:353). Uses
wget from busybox (already present in alpine:3.21) so no extra
apk install is needed. Interval 30s / timeout 5s / start-period 10s
/ retries 3 — conservative defaults safe for low-traffic single-user
instances.

Verified the built image reports the expected HEALTHCHECK via
`docker inspect` and that the probe succeeds against a live container.

Parent: PLAN-644.
2026-04-22 20:13:53 -04:00
xarmian a0b8abd4da fix: Dockerfile CMD needs 'server start' (server is a subcommand group) 2026-04-13 01:03:12 +00:00
xarmian 8095885cf2 fix: Dockerfile CMD should be 'server' not 'serve' 2026-04-13 01:03:12 +00:00
xarmian 0972347cf0 Fix svelte warnings and add build version info (#26)
* Fix all 17 svelte-check warnings across 7 components

- Add tabindex to toolbar role elements (BoardView, Editor)
- Replace nested buttons with div[role=button] in ListView group headers
- Add role="none" to click-to-close backdrop overlays (Editor, slug page)
- Fix label→span for non-input field labels (CreateWorkspaceModal)
- Add keyboard handlers to interactive divs (CreateWorkspaceModal drop zone, slug page modal)
- Remove unused .slash-backdrop CSS (Editor) and input[type=text] selector (CreateWorkspaceModal)
- Fix state_referenced_locally in RawMarkdownEditor ($state init)
- Add svelte-ignore for conditional tabindex false positive (ToastContainer)

* feat: add build version, commit hash, and timestamp to CLI and web UI

Inject version info via ldflags during build (Makefile, GoReleaser,
Dockerfile). Expose version/commit/build_time in the health API
endpoint and display it in the sidebar footer. Dev builds show
"dev (abc1234 ...)", releases show "v1.2.3 (abc1234 ...)".
2026-03-30 11:54:45 -04:00
xarmian a2e5a6622d Add Docker support and PAD_DATA_DIR config
- Multi-stage Dockerfile for building from source
- Dockerfile.goreleaser for GoReleaser-built release images
- GoReleaser config: publish multi-arch Docker images to ghcr.io
- Add PAD_DATA_DIR environment variable for configuring data directory
- Update README with Docker install option
- Add .dockerignore
2026-03-28 04:34:17 +00:00