Commit Graph

21 Commits

Author SHA1 Message Date
745a461688 Merge origin/main into feature/config-validation (TODO.md bookkeeping) 2026-08-07 16:57:44 +00:00
5d0b5f864e docs: record manual test pass of auth and encrypted URL flows (closes #49) (#50)
All checks were successful
check / check (push) Successful in 4s
closes #49

Records the P0 manual test pass in `TODO.md` per its Workflow section
(checked-off results into Completed Steps; cache size management and
eviction promoted to Next Step). `TODO.md` is the only changed file —
no production code changes, as the issue requires.

## Test setup

`pixad` built from `main` at `6573b9d` via `make build`, run on port
18099 with a throwaway local config (temp state dir, known
`signing_key`, `allowlist_hosts` including `s3.sneak.cloud`), driven
with curl using explicit cookie replay (session cookies are
`Secure`/`HttpOnly`/`SameSite=Strict`).

## Results — all six checks PASS

1. **Login form**: GET `/` → HTTP 200, `Pixa - Login` page with
   `name="key"` password form.
2. **Wrong key error**: POST `/` with `key=wrong-key` → HTTP 200 login
   page containing "Invalid signing key".
3. **Generator form**: POST `/` with the correct signing key → HTTP 303
   to `/` with `Set-Cookie: pixa_session=...; HttpOnly; Secure;
   SameSite=Strict`; GET `/` with that cookie → `Pixa - URL Generator`
   with the `/generate` form and logout link.
4. **Encrypted URL serves image**: POST `/generate` (ttl=3600) produced
   a `/v1/e/<token>/img.jpeg` URL → HTTP 200, `Content-Type:
   image/jpeg`, 800x600 baseline JPEG, 61706 bytes.
5. **Expired URL → 410**: a ttl=1 URL fetched after 3 s → HTTP 410 Gone
   with `{"error":"URL has expired","status":410,...}`.
6. **Logout**: GET `/logout` → HTTP 303 to `/` with `Set-Cookie:
   pixa_session=; Max-Age=0`; subsequent GET `/` → login form again.

Additionally, all nine checks in `scripts/manual-test.sh` passed
against the same server instance.

## Verification

`make check` green on the branch head (all tests, golangci-lint 0
issues, fmt-check clean) — the first fully green `make check` on a
`main`-derived branch under the current linter, confirming the #47/#48
fix on merged `main`.

Note for review: the test execution was performed this session; the
adversarial re-review (independently re-running the six flows) is still
pending and should happen before merge.

Co-authored-by: sneak <sneak@sneak.berlin>
Reviewed-on: #50
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-08-07 18:44:01 +02:00
2fb0801dc6 feat: validate configuration on startup, fail fast on bad config (closes #52)
Some checks failed
check / check (push) Failing after 42s
A config value that is set but unparseable or invalid now aborts
startup with an error naming the offending key and value; defaults
apply only to omitted keys. Unknown top-level config keys and unknown
metrics subkeys abort startup naming each unknown key, so typos like
whitelist_hosts fail immediately instead of being silently ignored. A
config file that exists at a standard location but fails to parse is
now a fatal error instead of being skipped with a warning. state_dir
is verified creatable and writable with a probe file before the
listener binds. Port must be in 1-65535 (fractional values are
rejected, not truncated), upstream_connections_per_host must be at
least 1, allowlist_hosts entries must be bare hostnames, sentry_dsn
must be a valid URL when set, and metrics credentials must be set
together. The stale signing_key comment in config.example.yml (keyless
mode was never implemented) now states the actual requirement.
TODO.md records the completed step per its Workflow section.
2026-08-07 16:37:30 +00:00
275e145a6d fix: set Secure/HttpOnly/SameSite on session cookies (closes #47) (#48)
All checks were successful
check / check (push) Successful in 5s
closes #47

Fixes the two remaining `gosec` findings on `main`, both `G124`
(http.Cookie missing or has insecure `Secure`, `HttpOnly`, or
`SameSite` attribute):

- `internal/session/session.go:84` (`CreateSession`, the login
  set-cookie path)
- `internal/session/session.go:128` (`ClearSession`, the logout
  delete-cookie path)

## What changed

- Both cookie-writing paths now unconditionally set `Secure: true`,
  `HttpOnly: true`, and `SameSite: http.SameSiteStrictMode`.
- The `secure` field (previously wired to `!config.Debug`) and the
  `sameSite` field are removed from `session.Manager`, and the dead
  secure-toggle parameter is removed from `session.NewManager`, which
  now takes only the signing key (reviewer-directed; the mechanical
  call-shape updates in `session_test.go` leave every assertion
  untouched).
- TDD per repo rules: the first commit adds
  `TestSessionCookieAttributesAlwaysSecure` (failing), asserting that
  every cookie emitted by the session manager carries `HttpOnly`,
  `Secure`, and `SameSite` of Lax or stricter, for both write paths.
  The second commit makes it pass.
- `TODO.md` updated per its Workflow section (Next Step completed,
  next Future Step promoted, stale "10 open findings" Status text
  corrected).

## Attribute choices and reasoning

- `Secure: true` always: the `G124` analyzer only accepts a constant
  `true` store, and there is no legitimate configuration in which the
  authentication cookie should be sent over plaintext HTTP. The old
  behavior disabled `Secure` whenever `debug` was on. Local development
  over `http://localhost` keeps working: browsers treat `localhost` as
  a trustworthy origin and accept `Secure` cookies there. Any
  plain-HTTP flow on a non-localhost host will no longer keep a
  session, which is the point of the fix.
- `SameSite: Strict` (unchanged from current production behavior, and
  stricter than the Lax minimum): the login form is a same-origin POST
  to `/` followed by a same-site redirect, so `Strict` breaks nothing.
- `HttpOnly: true` (unchanged).

## Verification

`make check` (tests, golangci-lint, fmt-check) is fully green on the
branch head `cb9e14e`: all tests pass and the linter reports 0 issues,
independently confirmed by the reviewer in a fresh worktree. Commit
history: `ca15f52` (failing test) → `02ca16a` (fix + TODO.md, closes
#47) → `cb9e14e` (drop the dead `NewManager` parameter).

Co-authored-by: sneak <sneak@sneak.berlin>
Reviewed-on: #48
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-08-07 17:41:03 +02:00
504afea4f8 scripts-to-rule-them-all (#45)
All checks were successful
check / check (push) Successful in 4s
Reviewed-on: #45
Co-authored-by: sneak <sneak@sneak.berlin>
Co-committed-by: sneak <sneak@sneak.berlin>
2026-07-07 02:14:03 +02:00
2fb909283d Update TODO.md: standard structure and Workflow section (#44)
All checks were successful
check / check (push) Successful in 5s
Reviewed-on: #44
Co-authored-by: sneak <sneak@sneak.berlin>
Co-committed-by: sneak <sneak@sneak.berlin>
2026-07-06 21:20:56 +02:00
2e934c8894 fix: QA audit fixes for 1.0/MVP readiness (#25)
All checks were successful
check / check (push) Successful in 5s
closes #24

## QA Audit Fixes

This PR addresses issues found during the 1.0/MVP QA audit.

### Changes

1. **TODO.md: Mark AVIF encoding as done** — AVIF encoding is fully implemented via govips in `processor.go` but was still listed as a TODO item.

2. **scripts/manual-test.sh: Fix form field names** — The manual test script was using wrong field names:
   - Login form: was sending `password=...`, should be `key=...` (matching the HTML form's `name="key"`)
   - Generator form: was sending `source_url`, `fit_mode` — should be `url`, `fit` (matching the handler's `r.FormValue()` calls)
   - This means **the manual test script never actually worked** — login always failed silently because the `key` field was empty.

### Full QA Audit Results

The comprehensive QA audit report has been posted as a comment on [issue #24](#24).

Co-authored-by: user <user@Mac.lan guest wan>
Reviewed-on: #25
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-03-15 17:58:13 +01:00
70d55977c0 Add WebP encoding support
Uses github.com/gen2brain/webp - a CGO-free library that uses WASM via
wazero runtime for encoding. WebP decoding was already supported.

- Add gen2brain/webp dependency for encoding
- Implement WebP encoding in processor.go
- Add FormatWebP to SupportedOutputFormats
- Re-enable WebP option in generator form dropdown
- Mark WebP encoding as complete in TODO.md
2026-01-08 11:55:45 -08:00
aab43db44a Add WebP and AVIF encoding support to P0 TODO 2026-01-08 11:12:59 -08:00
02de534cc2 Reorganize TODO.md: remove completed, prioritize for 1.0
P0 Critical: Manual testing, cache eviction, config validation
P1 Production: Blocked networks, rate limiting, EXIF stripping
P2 Nice to have: Everything else
2026-01-08 10:41:00 -08:00
774ee97ba1 Update TODO.md: mark HTTP response handling items complete
Completed:
- ETag generation and validation
- Conditional requests (If-None-Match)
- HEAD request support
- Metrics endpoint with auth (already implemented)
2026-01-08 10:09:10 -08:00
6f423af65d Update TODO.md: mark graceful shutdown and sanitization as complete 2026-01-08 10:02:29 -08:00
90be4e7763 Update TODO.md: mark security validations as complete 2026-01-08 08:50:37 -08:00
857be30e82 Update TODO.md: mark auth/encrypted URLs feature as complete 2026-01-08 08:43:23 -08:00
f601e17812 Add implementation plan for auth and encrypted URLs feature 2026-01-08 07:39:31 -08:00
cc0fd29954 Update TODO.md with completed image processing items 2026-01-08 04:02:53 -08:00
b14c897408 Update TODO.md with completed caching layer items 2026-01-08 03:36:05 -08:00
9ff44b7e65 Update TODO.md with completed core features 2026-01-08 03:02:24 -08:00
a9573a4b10 Mark project setup tasks complete in TODO.md 2026-01-08 02:53:49 -08:00
4ef9141960 Add Makefile with check, lint, test, fmt targets
- check: default target, runs fmt-check, lint, and test
- fmt-check: verifies code is properly formatted
- fmt: formats code with gofmt
- lint: runs golangci-lint
- test: runs go test
- build: builds pixad binary with version info
- clean: removes build artifacts
2026-01-08 01:51:46 -08:00
12f6f6fe75 Add TODO.md with implementation checklist
Complete linear checklist of tasks to implement the pixa caching
image reverse proxy server, covering project setup, core features,
caching, image processing, security, and operational concerns.
2026-01-08 01:51:15 -08:00