Commit Graph
90 Commits
Author SHA1 Message Date
andrew 74902c0fc7 adding intl
Sync GitHub / sync (push) Successful in 9s
PHP Test / test (push) Successful in 1m11s
Tests / test (push) Successful in 1m11s
Docker Publish / docker (push) Successful in 17m19s
Push Develop / docker (push) Successful in 17m19s
2026-09-25 10:22:08 -04:00
andrew bd2f5cbac3 removed problematic opcache line from dockerfile
Sync GitHub / sync (push) Successful in 7s
Docker Publish / docker (push) Successful in 7m6s
Push Develop / docker (push) Successful in 7m6s
PHP Test / test (push) Successful in 1m5s
Tests / test (push) Successful in 1m5s
2026-09-25 09:49:46 -04:00
andrew 51e921f54f now syncing github via shared workflow
Sync GitHub / sync (push) Successful in 7s
Docker Publish / docker (push) Failing after 49s
Push Develop / docker (push) Failing after 49s
PHP Test / test (push) Successful in 1m10s
Tests / test (push) Successful in 1m10s
2026-09-25 09:03:42 -04:00
andrew ba8924a244 Merge pull request 'docker to be more inline with other projects and best practices' (#18) from feat/refactoring into main
Sync GitHub / sync (push) Successful in 8s
Docker Publish / docker (push) Failing after 54s
Push Develop / docker (push) Failing after 54s
PHP Test / test (push) Successful in 57s
Tests / test (push) Successful in 57s
Reviewed-on: #18
2026-09-25 08:50:24 -04:00
lyra 538bd74100 docker to be more inline with other projects and best practices
PHP Test / test (pull_request) Successful in 52s
Tests / test (pull_request) Successful in 52s
2026-09-25 08:25:55 -04:00
andrew db0cf77049 normalizing workflow and build files
Sync GitHub / sync (push) Successful in 6s
Docker Publish / docker (push) Successful in 18s
Push Develop / docker (push) Successful in 18s
PHP Test / test (push) Successful in 1m5s
Tests / test (push) Successful in 1m5s
2026-09-24 16:41:42 -04:00
lyra ef924472a3 normalizing workflow content
Sync GitHub / sync (push) Successful in 7s
Docker Publish / docker (push) Successful in 22s
Push Develop / docker (push) Successful in 23s
Tests / test (push) Successful in 1m19s
2026-09-24 09:05:07 -04:00
lyra 539385c438 finish moving to central CI.
Sync GitHub / sync (push) Successful in 7s
Tests / test (push) Successful in 1m12s
Docker Publish / docker (push) Successful in 21s
Push Develop / docker (push) Successful in 22s
2026-09-23 17:37:49 -04:00
lyra eed6b4dbff moment of truth, trying to use central CI for docker image build, starting with just develop.
Sync GitHub / sync (push) Successful in 7s
Tests / test (push) Successful in 1m12s
Docker Publish / docker (push) Successful in 5m1s
Push Develop / docker (push) Successful in 5m1s
2026-09-23 17:34:15 -04:00
andrew 2b61a43f60 Merge pull request 'build: define the Docker build in docker-bake.hcl' (#17) from chore/docker-bake into main
Sync GitHub / sync (push) Successful in 7s
Tests / test (push) Successful in 1m19s
Push Develop / docker (push) Successful in 4m41s
Reviewed-on: #17
Reviewed-by: Andrew <andrew@digitaladapt.com>
2026-09-23 17:30:04 -04:00
lyra abe94c6238 build: define the Docker build in docker-bake.hcl
Tests / test (pull_request) Successful in 1m15s
The build was described in two places kept in step by hand: the Dockerfile, and
the `with:` block of each docker workflow file. This moves the parts CI actually
decides — Dockerfile target, platforms, tags, build args — into docker-bake.hcl,
so the build is version-controlled with the code and reviewable in a diff.

Tags are byte-identical to the current workflows, verified with
`buildx bake --print`:

  main push   -> digitaladapt/preauth:develop
  tag v1.2.0  -> digitaladapt/preauth:latest AND digitaladapt/preauth:1.2.0

Dockerfile: the final stage gains `AS app` so bake can target it. Naming the
last stage is a no-op for a plain `docker build` — it is still the default
target — so `docker build .` behaves exactly as before.

THREE THINGS FOUND WHILE DOING THIS
-----------------------------------

1. `buildx bake --print` does NOT read the Dockerfile, so it accepts a `target`
   naming no stage. preauth's final stage was unnamed, so `target = "app"` would
   have failed at build time in CI *after the push*, with --print reporting
   success. Fixed by naming the stage.

2. The `bake` backend in docker-publish.yaml sets no layer cache, while the
   `action` backend it replaces sets cache-from/cache-to: type=gha. Neither
   existing bake user in the portfolio sets one either, so every bake build in
   the portfolio runs cold. preauth compiles APCu from source (pecl) in both
   stages, so this would have been a real regression. The bake file now sets the
   gha cache, with the override for local builds documented.

3. `ARG MAX_REQUESTS` has been documented in the Dockerfile since the Symfony
   8.1 upgrade, but no workflow ever passed it, so CI silently built with the
   500 default. It is now an explicit named variable, overridable per build.

The workflow callers that select the bake backend are NOT in this commit:
.gitea/workflows/ is protected by a pre-receive hook and only changes via a
trusted ref. They are staged in the working tree.

Verified: Dockerfile stage/target contract holds; bake file parses and resolves
under buildx 0.37; 313 tests pass; conformance 31/34 with callers staged.
2026-09-23 21:01:53 +00:00
andrew 1e186c9354 Merge pull request 'chore: adopt shared Guiding Light configs, fix conformance gaps (18/34 → 30/34)' (#16) from chore/adopt-guiding-light into main
Sync GitHub / sync (push) Successful in 8s
Tests / test (push) Successful in 1m8s
Push Develop / docker (push) Successful in 6m53s
Reviewed-on: #16
Reviewed-by: Andrew <andrew@digitaladapt.com>
2026-09-23 16:40:51 -04:00
lyra 2064153cd3 chore: adopt shared Guiding Light configs and fix conformance gaps
Tests / test (pull_request) Successful in 1m10s
Brings preauth from 18/34 to 30/34 conformance (auth-gateway profile). The
remaining four checks all depend on files this branch cannot change (see below).

PHP toolchain (§1)
  - require.php  >=8.4 -> ^8.5, and pin config.platform to 8.5.0. The old
    constraint also permitted PHP 9, which is not a promise we can keep.
    composer.lock regenerated with --lock: content-hash + platform-overrides
    only, zero dependency version movement.
  - friendsofphp/php-cs-fixer  * -> ^3.95. A wildcard meant CI was not
    reproducible.

PHPStan (§2.2)
  - vendor the shared phpstan.neon.dist (level 6) + a generated baseline.
    187 errors are captured rather than fixed; the baseline should only shrink
    from here.
  - add phpstan/phpstan:^2.1 to require-dev.

Code style (§8.2)
  - vendor the shared .php-cs-fixer.dist.php (@Symfony + @Symfony:risky +
    declare_strict_types) and apply it: 59 of 67 files reformatted.
  - Verified this is a formatting change, not a behaviour change: all 313 tests
    pass after the reformat, all in_array() calls already passed strict=true,
    and the remaining edits are @Symfony:risky idiom (yoda conditions, \count(),
    self:: over the class name).

Repository layout (§4.4)
  - docs/{Caddyfile,compose.yaml,example.env} -> docs/examples/, with
    example.env becoming the conventional .env.example. This is the layout
    GUIDING-LIGHT already cites preauth as doing correctly — it just needed
    renaming.
  - update the four readme.md references and a stale compose.yaml comment.
  - docs/v1.1-plan.md references are left alone deliberately: it is a historical
    plan recording what was done at the time, not live documentation.

Licence and security policy (§7)
  - add LICENSE (uniform MIT, matching composer.json).
  - add SECURITY.md describing the actual threat model: per-request
    allow/intercept, no caching of the login flow, app-set security headers,
    TOTP, and the fact that REMOTE_USER is trusted input.

Mobile accessibility (§3.3a)
  - templates/base.html.twig: drop maximum-scale=1 and add viewport-fit=cover.
    preauth was the one app already past the font-size precondition (controls
    render at 21.6px = 0.9em x 24px), so removing the lock is safe here and
    restores pinch-zoom for Android users.

Conformance tooling (§8.2)
  - vendor .ci/conformance.sh and .ci/css-control-size.py so the check runs
    from a checkout rather than fetching from the LAN-only private/ci.
  - .editorconfig synced from the version that keeps the Caddyfile tab rule.

Not included (blocked by the .gitea/workflows pre-receive hook):
  - ci-composer-audit, ci-composer-validate, ci-reusable-workflows.
    Workflow files may only change via a trusted ref, so the caller files are
    staged but not committed.

Also not included: dockerfile-nonroot (§6.4). Adding USER to an image with
VOLUME [/config, /data] changes volume ownership and needs an actual container
build/run to verify, so it goes in its own change.
2026-09-23 20:13:45 +00:00
andrew 054b8ef48f Merge pull request 'fix: never cache the login flow (stale pre-auth responses in Safari)' (#12) from fix/login-flow-cache-control into main
Sync GitHub / sync (push) Successful in 10s
Tests / test (push) Successful in 1m35s
Push Develop / docker (push) Successful in 6m3s
Push Docker / docker (push) Successful in 8m45s
Reviewed-on: #12
Reviewed-by: Andrew <andrew@digitaladapt.com>
v1.2.0
2026-09-14 21:56:59 -04:00
lyra 5258e175a1 fix: never cache the login flow (stale pre-auth responses in Safari)
Tests / test (pull_request) Successful in 1m8s
The login page, failed logins, redirects, and rate-limit/error pages could
be stored by the browser (Symfony's default 'no-cache, private' still
permits storage — it only requires revalidation). Older Safari builds may
then replay a stale pre-auth response on refresh, appearing to log the
user back out, or show a previous session after logging in again.

- SecurityHeadersListener: send strict anti-caching headers on non-2xx
  responses only (no-store/no-cache/must-revalidate/proxy-revalidate,
  max-age=0, s-maxage=0 + Pragma, Expires, Surrogate-Control, Vary: *).
  2xx grants (already-authenticated / public access) are consumed by
  Caddy's forward_auth check and never reach the browser, and protected
  services' own cache headers must stay untouched.
- templates/_script.html.twig: fetch() with cache: 'no-store'; follow
  redirects with location.replace() to keep the login page out of history
  and the back-forward cache.
- docs/Caddyfile: reusable (preauth_no_store) snippet imported into every
  forward_auth block, using header_down so the guarantee holds at the edge
  (verified: replaces conflicting upstream values, leaves service
  responses alone).
- tests: unit coverage for the listener and functional coverage for the
  full HTTP kernel (login/failure/redirect/rate-limit not cacheable;
  200 grants untouched); asserts the rendered page carries the JS changes.
- readme/CHANGELOG updates.
2026-09-14 19:31:44 -04:00
andrew 2f7ae31ba1 Merge pull request 'feat: upgrade Symfony 7.4 → 8.1, drop runtime/frankenphp-symfony' (#11) from feat/symfony-8.1-upgrade-plan into main
Sync GitHub / sync (push) Successful in 8s
Tests / test (push) Successful in 1m21s
Push Develop / docker (push) Successful in 4m49s
Reviewed-on: #11
Reviewed-by: Andrew <andrew@digitaladapt.com>
2026-09-12 16:51:29 -04:00
lyra baf976a8e6 feat: restore worker recycle limit via Caddyfile max_requests (default 500)
Tests / test (pull_request) Successful in 1m4s
The removed runtime/frankenphp-symfony package force-restarted the
worker after FRANKENPHP_LOOP_MAX requests (default 500) - memory-leak
paranoia the built-in 8.1 runner intentionally doesn't reimplement.

Restore the behavior natively so the upgrade is a no-op operationally:
- Caddyfile: global frankenphp block with max_requests {$MAX_REQUESTS}
  - per-thread graceful restarts, other threads keep serving
- Dockerfile: ARG/ENV MAX_REQUESTS=500 bakes the same default the old
  package had, overridable at docker build or runtime (-e, 0 disables)
- Stock FRANKENPHP_CONFIG env var remains the full-config escape hatch
- Documented in readme env table, docs/example.env, CHANGELOG, and the
  upgrade plan (phase-4 staging note now checks thread recycling)
2026-09-08 06:15:20 -04:00
lyra af4d2a4ac7 docs: record Symfony 8.1 upgrade results, update stack references
Tests / test (pull_request) Successful in 1m7s
- Plan doc: mark Phases 0-3 + worker-mode state audit complete with
  verified results; resolve open questions (all src/ services are final
  readonly - no ResetInterface needed under kernel-reusing runner)
- CHANGELOG: Unreleased entries for the 8.1 bump and the
  runtime/frankenphp-symfony removal (incl. FRANKENPHP_LOOP_MAX note)
- ROADMAP: current stack now Symfony 8.1; webauthn research note updated
- bin/dev.sh: correct stale PHP requirement comment
2026-09-07 22:46:22 -04:00
lyra c743a1baac feat: upgrade Symfony 7.4 -> 8.1, drop runtime/frankenphp-symfony
- All symfony/* constraints bumped 7.4.* -> 8.1.* (resolved to 8.1.2-8.1.6)
- Removed runtime/frankenphp-symfony: symfony/runtime 8.1 handles
  FrankenPHP worker mode natively via FrankenPhpWorkerRunner; deleted
  the extra.runtime class override so GenericRuntime auto-detects it
- phpunit 13.3.2, twig 3.28, otphp 11.5 ride along
- Deprecation sweep on 7.4 was clean (failOnDeprecation suite, zero hits)
- Verified: bin/console about boots on 8.1.6; 295 tests / 612 assertions
  green after the bump
2026-09-07 22:40:17 -04:00
lyra 3f1778cd6b docs: add Symfony 7.4 -> 8.1 upgrade plan
Covers deprecation sweep gate, composer.json constraint bumps to 8.1.*,
and removal of runtime/frankenphp-symfony (FrankenPHP worker mode is
handled natively by symfony/runtime in 8.x). Includes config recipe
re-sync, Docker/CI notes, phased rollout with rollback, and open
questions (kernel-reset audit for worker mode).
2026-09-07 22:26:00 -04:00
andrew 33181f11d8 testing branch is safe now that git hook protections have been setup
Sync GitHub / sync (push) Successful in 10s
Tests / test (push) Successful in 1m10s
Push Develop / docker (push) Successful in 4m44s
Push Docker / docker (push) Successful in 4m53s
v1.1.5
2026-08-30 22:24:50 -04:00
andrew bb2cc3ce49 only test and push select branches
Sync GitHub / sync (push) Successful in 8s
Tests / test (push) Successful in 1m9s
Push Develop / docker (push) Successful in 4m48s
2026-08-27 21:55:07 -04:00
andrew e4f54769e6 use main branch workflow
Sync GitHub / sync (push) Successful in 7s
Tests / test (push) Successful in 1m1s
Push Develop / docker (push) Successful in 4m45s
Push Docker / docker (push) Successful in 10m28s
v1.1.4
2026-08-25 20:22:12 -04:00
andrew b75a16a781 Merge remote-tracking branch 'origin/fix/ci-github-rate-limit' into develop
Sync GitHub / sync (push) Successful in 8s
Push Develop / docker (push) Successful in 4m55s
Tests / test (push) Successful in 59s
Push Docker / docker (push) Successful in 4m42s
v1.1.3
2026-08-21 16:11:31 -04:00
andrew 9111958bcf Merge branch 'main' into develop 2026-08-21 16:10:30 -04:00
andrew 95dc6bf0ce Merge branch 'main' into fix/ci-github-rate-limit
Sync GitHub / sync (push) Successful in 6s
2026-08-20 16:27:52 -04:00
lyra 472abfdf89 fix(ci): cache composer deps and authenticate to GitHub
Tests / test (pull_request) Successful in 1m21s
Tests / test (push) Successful in 1m30s
Push Develop / docker (push) Successful in 5m12s
Sync GitHub / sync (push) Successful in 9s
The test workflow was hitting GitHub's unauthenticated API rate
limit (60 req/hour) when downloading 95 packages via composer
install --prefer-dist, causing 429 Too Many Requests errors.

Two fixes applied:
1. Cache Composer's download cache (~/.composer/cache) keyed on
   composer.lock hash, so repeated CI runs don't re-download
   packages at all.
2. Configure GitHub OAuth token via SYNC_GITHUB_TOKEN secret to
   raise the rate limit to 5,000 req/hour for cache misses.
2026-08-17 12:03:14 -04:00
lyra e2780ca5f6 fix: allow same-origin fetch in CSP when inline login script is used
Tests / test (pull_request) Successful in 49s
Sync GitHub / sync (push) Successful in 9s
Tests / test (push) Successful in 1m1s
Push Develop / docker (push) Successful in 4m47s
Push Docker / docker (push) Successful in 7m35s
When subdomain redirection is off, the login form is served inline on
the protected host and submission happens via a same-origin fetch() call
in _script.html.twig. The CSP default-src 'none' was blocking that
fetch (connect-src falls back to default-src).

Add connect-src 'self' to the CSP only when the request is not on the
auth subdomain (i.e. when the inline script is present). On the auth
subdomain the form POSTs normally with no inline script, so the stricter
policy still applies there.

This is the least-privilege relaxation: only same-origin connections,
only on pages that need them.
v1.1.2
2026-08-17 11:27:46 -04:00
andrew 7a68c933ce Merge pull request 'fix: handle host-prefixed root path in PublicPathMatcher' (#8) from fix/public-path-host-root into main
Push Develop / docker (push) Successful in 4m44s
Sync GitHub / sync (push) Successful in 7s
Tests / test (push) Successful in 45s
Push Docker / docker (push) Successful in 4m43s
Reviewed-on: #8
Reviewed-by: Andrew <andrew@digitaladapt.com>
v1.1.1
2026-08-13 16:28:05 -04:00
andrew 55f8e9e84c Merge branch 'main' into fix/public-path-host-root
Sync GitHub / sync (push) Successful in 9s
Tests / test (pull_request) Successful in 1m16s
2026-08-13 15:43:54 -04:00
lyra e3cd8c6739 fix: handle host-prefixed root path in PublicPathMatcher
Sync GitHub / sync (push) Successful in 6s
Tests / test (pull_request) Successful in 1m3s
The host-prefix regex required at least one character after the slash
(/\+.+/), so a pattern like 'code.example.com/' was silently dropped
instead of matching the root path '/'. Changed \+.+ to \+.* so the
trailing slash alone is accepted as the path '/'.

Added tests covering the exact bug scenario from PUBLIC_PATHS
config: 'code.digitaladapt.com/,code.digitaladapt.com/public/**'
2026-08-13 14:30:52 -04:00
lyra 235a7866b3 fix: remove incorrect CSS escaping on color values
Tests / test (pull_request) Successful in 1m5s
Push Develop / docker (push) Successful in 6m43s
Sync GitHub / sync (push) Successful in 8s
Tests / test (push) Successful in 54s
The Twig |e('css') filter was escaping '#' (0x23) to '\23 ' in hex
color values (bg_color, fg_color, error_color), causing browsers to
not recognize them as valid CSS colors. These are admin-configured
environment variables, not user input, so CSS escaping is unnecessary.
2026-08-13 12:07:20 -04:00
lyra c7585e720a feat: add self-bootstrapping dev server script (bin/dev.sh)
Tests / test (pull_request) Successful in 50s
Push Develop / docker (push) Successful in 8m39s
Sync GitHub / sync (push) Successful in 7s
Tests / test (push) Successful in 57s
Manages a local PHP dev server for end-to-end development and testing.
Binds to 0.0.0.0:8773, accessible via Caddy at
https://preauth.lyra-dev.devgnome.com.

Features:
- Self-bootstrapping: installs PHP 8.4 + extensions (including APCu,
  which is critical for nonce cache, rate limiter, and session storage),
  Composer, and project dependencies if missing. Survives terminal
  resets/reboots.
- Enables apc.enable_cli=1 for console commands (matches Dockerfile)
- Subcommands: start, stop, status, restart
- Sets APP_SHARE_DIR to var/share for filesystem session persistence
- Clears dev cache on start

No database needed — preauth uses APCu + filesystem cache exclusively.

Port assignment: P-R-E = 7-7-3 → 8773
2026-08-13 11:56:55 -04:00
andrew 66b960ccea Merge pull request 'feat: v1.1 — public rate-limited access' (#5) from feat/v1.1-public-access into main
Push Develop / docker (push) Successful in 4m47s
Sync GitHub / sync (push) Successful in 7s
Tests / test (push) Successful in 55s
Push Docker / docker (push) Successful in 4m46s
Reviewed-on: #5
Reviewed-by: Andrew <andrew@digitaladapt.com>
v1.1.0
2026-08-13 01:30:13 -04:00
andrew 17c2d525ff Merge branch 'main' into feat/v1.1-public-access
Sync GitHub / sync (push) Successful in 13s
Tests / test (pull_request) Successful in 54s
2026-08-13 01:19:08 -04:00
andrew 72c41fec77 Merge pull request 'fix: v1.0 release — security hardening, code quality, and documentation' (#4) from fix/v1.0-must-fix into main
Push Develop / docker (push) Successful in 4m47s
Sync GitHub / sync (push) Successful in 8s
Tests / test (push) Successful in 57s
Push Docker / docker (push) Successful in 4m48s
Reviewed-on: #4
Reviewed-by: Andrew <andrew@digitaladapt.com>
v1.0.0
2026-08-12 22:31:59 -04:00
lyra 29e471c536 Merge branch 'fix/v1.0-must-fix' into feat/v1.1-public-access
Push Develop / docker (push) Successful in 6m1s
Sync GitHub / sync (push) Successful in 7s
Tests / test (push) Successful in 1m3s
2026-08-12 11:21:42 -04:00
lyra 44e4c60f80 fix: restore develop branch trigger support for CI workflows
Tests / test (pull_request) Successful in 1m1s
Push Develop / docker (push) Successful in 6m29s
Sync GitHub / sync (push) Successful in 10s
Tests / test (push) Successful in 1m0s
Re-adds 'develop' to push triggers in develop.yaml and tests.yaml
so the :develop Docker image can be built from the develop branch,
enabling dev testing without requiring a merge to main.
2026-08-12 11:21:37 -04:00
lyra 5563999525 feat: public rate-limited access for v1.1
Sync GitHub / sync (push) Successful in 8s
Add PublicAccessListener (priority 84) that allows rate-limited
unauthenticated access to configured public paths. Authenticated users
bypass this listener entirely via AcceptListener/AllowListener.

New components:
- PublicPathMatcher service with wildcard path matching (* and **)
  and optional host-prefix scoping
- PublicAccessListener applying per-IP rate limiting to public paths
- Separate public_limiter compound rate limiter (burst + sustained)
- publicRateLimitCache pool (APCu in prod, array in tests)

New env vars:
- PUBLIC_PATHS (comma-separated path patterns, empty = disabled)
- PUBLIC_BURST_COUNT/PUBLIC_BURST_TIME (default 100/60s)
- PUBLIC_UPPER_COUNT/PUBLIC_UPPER_TIME (default 500/3600s)

Tests: 52 new tests (29 unit for PublicPathMatcher, 12 unit for
PublicAccessListener, 11 functional for PublicAccessFlowTest).
Total: 293 tests, 605 assertions, all passing.
PHP CS Fixer: 0 of 63 files need fixing.

Documentation: README, CHANGELOG, ROADMAP, Caddyfile, example.env
all updated with public access configuration and examples.
2026-08-12 09:26:50 -04:00
lyra 9ad54f8e2a feat: configurable Remote-User header (design consideration 1.2)
Sync GitHub / sync (push) Successful in 7s
Tests / test (pull_request) Successful in 58s
Add REMOTE_USER env var with four modes:
- session (default): sends session id, backward-compatible
- static: sends a fixed string (REMOTE_USER_STATIC)
- mapped: looks up session id in REMOTE_USER_MAP
- none: omits the header entirely

New RemoteUserMode enum, ConfigBag parsing/validation, and
StringTrait::authSuccessResponse resolves the header value based
on the configured mode. AcceptListener now receives ConfigBag as
a constructor dependency.

Addresses design consideration 1.2 (Remote-User header value is
user-controlled) from DESIGN_CONSIDERATIONS.md.

241 tests pass, 0 cs-fixer violations.
2026-08-11 22:48:52 -04:00
lyra 2258839bd6 docs: update DESIGN_CONSIDERATIONS.md to reflect addressed items
Sync GitHub / sync (push) Successful in 8s
- Mark all resolved items with ✅ and describe the fix applied
- Mark remaining open items with ⬜ and keep recommendations
- Add new sections for items discovered during the fix work:
  - 1.7 CSS injection in style template
  - 1.8 ->json null safety
  - 1.9 validReturn() parse_url false check
  - 1.10 Incomplete TLD list
  - 2.8 Duplicated response construction
  - 2.9 Duplicated constants
  - 5.3 Kernel::terminate() try/finally
  - 9. CI & Workflows (tag format, stale branches, publish.yaml)
- Update 'What's Done Well' to reflect new improvements
- Add summary noting this is a living document tracking the
  fix/v1.0-must-fix branch state
2026-08-11 17:02:27 -04:00
lyra 408d75dda1 chore: nice-to-have improvements for v1.0
Sync GitHub / sync (push) Successful in 8s
Code quality:
- Create AppConstants class with shared constants:
  - FAR_FUTURE_DATE (replaces duplicated '2999-12-31' strings)
  - MAX_INPUT_LENGTH (replaces duplicated 128 in Payload and StringTrait)
- Extract duplicated 'hi $id' response body into StringTrait::authSuccessResponse()
  method, used by AcceptListener, AllowListener, and LoginManager
- Add missing @throws InvalidArgumentException annotations to
  MonitorCacheKeys (getItem, hasItem, deleteItem, deleteItems, commit)

Configuration:
- Add proper env var type casting in services.yaml:
  - COOKIE_TTL → env(int:)
  - SUBDOMAIN_REDIRECT → env(bool:)
  - IP_TTL → env(int:)
  - TEAPOT → env(bool:)

Documentation:
- Create CONTRIBUTING.md with development setup, code style,
  testing guidelines, and PR process
2026-08-11 16:37:23 -04:00
lyra b89070e985 fix: should-fix items for v1.0 release
Documentation:
- Create CHANGELOG.md with full version history (v0.0.1 through unreleased)
- Rewrite README with comprehensive setup guide, configuration reference,
  architecture overview, security model, and feature list
- Update ROADMAP.md: fix branch status table, mark completed security
  review items, update TOTP leeway description
- Fix 'centeral' typo in docs/Caddyfile
- Remove TODO comment from docs/compose.yaml
- Add DESIGN_CONSIDERATIONS.md (design review document)

Code quality:
- Extract duplicated cookie name/domain logic into CookieNameTrait
  methods: sessionCookieName() and sessionCookieDomain()
- Update AcceptListener, AllowListener, InterceptListener, and
  LoginManager to use the shared methods
- Remove fragile cross-file coupling comment between LoginManager
  and InterceptListener

Error handling:
- Wrap cache operations in AcceptListener and AllowListener with
  try/catch to fail closed (don't authenticate on cache errors)
- Log cache errors at error level instead of propagating as 500s
- Early return pattern in AcceptListener and AllowListener for
  cleaner control flow
2026-08-11 16:35:27 -04:00
lyra d2eb914637 fix: must-fix items for v1.0 release
Security:
- Add SecurityHeadersListener (X-Content-Type-Options, X-Frame-Options,
  CSP, Referrer-Policy, HSTS)
- Replace document.write() with document.documentElement.innerHTML
  in login JS to avoid CSP violations
- Add CSS escaping (|e('css')) to env color values in _style.html.twig
- Document CSRF protection model: nonce serves as CSRF token for POST
  form path (single-use, server-generated, 120s TTL)
- Reduce TOTP verification window from 10 periods (±5 min) to 1 (±30s)
- Remove hardcoded APP_SECRET from bin/franken.sh (now uses env or
  generates random)
- Remove backup code values from debug log output
- Add .env to .gitignore

Bug fixes:
- Fix ->json access on possibly-null  in LoginListener
  (uses null-safe operator ?->)
- Fix validReturn() not checking false from parse_url (could cause
  TypeError on malformed URLs)
- Add isHit() race condition check in AcceptListener and AllowListener
- Add try/finally in Kernel::terminate() so parent::terminate() always
  runs even if persist() throws
- Add input validation to GenerateBackupCodesCommand (reject count < 1)
- Use Response::HTTP_INTERNAL_SERVER_ERROR constant in GetTotpTrait
  instead of literal 500

Docker/CI:
- Explicitly install curl in Docker final image (needed for healthcheck)
- Update workflow tag pattern to v*.*.* (standardize on v-prefix)
- Extract version without v-prefix for Docker image tag
- Remove stale develop branch from CI triggers
- Fix publish.yaml git remote add to use set-url on re-runs

Code quality:
- Add declare(strict_types=1) to all interface files
- Add #[AsCommand] attribute to GenerateBackupCodesCommand
- Fix BackupCodeInterface default count to match implementation (10)
- Lowercase host before TLD lookup in DomainManager
- Expand TLD list with many missing multi-part TLDs (.com.au, .co.jp,
  .com.br, .co.kr, .com.tw, .co.za, etc.) to prevent open redirect
  vulnerabilities
- Disable unused Symfony sessions in framework.yaml

Tests:
- Update DomainManagerTest for corrected TLD parsing (.com.au, .co.jp,
  .com.br now correctly recognized as multi-part)
- Update GetTotpTraitTest for corrected error message
- Update GenerateBackupCodesCommandTest: zero count now throws exception
2026-08-11 16:33:00 -04:00
andrew c0bda8aeec Merge pull request 'chore: add php-cs-fixer with PSR-12 config and CI check' (#3) from chore/add-php-cs-fixer into main
Push Develop / docker (push) Successful in 4m48s
Sync GitHub / sync (push) Successful in 8s
Tests / test (push) Successful in 1m14s
Push Docker / docker (push) Successful in 4m44s
Reviewed-on: #3
0.10.0
2026-08-11 09:58:51 -04:00
lyra cb378e20bc chore: add php-cs-fixer with PSR-12 config and CI check
Sync GitHub / sync (push) Failing after 5s
Tests / test (pull_request) Successful in 49s
- Add friendsofphp/php-cs-fixer to require-dev
- Create .php-cs-fixer.dist.php configured for @PSR12 ruleset
- Add php-cs-fixer dry-run step to CI pipeline
- Auto-fix existing PSR-12 violations
- Document code style tooling in readme.md
2026-08-11 08:30:05 -04:00
lyra 6b5a711fa9 Fix docs, add .dockerignore, fix base64url padding, fix typo
Sync GitHub / sync (push) Successful in 7s
Tests / test (pull_request) Successful in 42s
- Add .dockerignore to exclude .git, vendor, var, tests, docs, .env
  and other non-build files from Docker context
- Fix broken base64url padding in src/Data/Payload.php: str_pad was
  a no-op because the length argument was always < string length.
  Replaced with correct str_repeat approach
- Fix typo in bin/franken.sh: digtialadapt → digitaladapt
- Add comment to bin/franken.sh noting it's a dev utility
- Remove config/reference.php from git tracking (auto-generated file)
  and add to .gitignore
- Fix readme.md: env.example → example.env (matches actual filename)
2026-08-10 18:55:19 -04:00
andrew 95ab77db2a added roadmap for where we are aiming to take this project
Push Develop / docker (push) Successful in 4m43s
Sync GitHub / sync (push) Successful in 6s
Tests / test (push) Successful in 47s
2026-08-07 09:25:56 -04:00
andrew d6bcbf661e Merge pull request 'Add PHPUnit test suite — 222 tests, 100% code coverage' (#1) from Lyra into main
Push Develop / docker (push) Successful in 7m5s
Sync GitHub / sync (push) Successful in 8s
Tests / test (push) Successful in 46s
Push Docker / docker (push) Successful in 4m44s
First AI contribution to main branch, a full suite of tests, thank you GLM-5.2.
0.9.0
2026-08-07 09:13:16 -04:00
lyra de2a382cbf Add Gitea workflow to run test suite on push and PR
Sync GitHub / sync (push) Successful in 7s
Tests / test (pull_request) Successful in 1m58s
2026-08-07 09:06:32 -04:00