484 Commits
Author SHA1 Message Date
renovate[bot] af68a4fa1c Update getsentry/action-release action to v3.7.2 (#4561) 2026-10-22 07:46:34 +01:00
renovate[bot] b1bea44cd3 Update github/codeql-action digest to 9b32540 (#4555)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-21 20:03:02 +01:00
renovate[bot] 11d8d69726 Update github/codeql-action digest to 6f2ac81 (#4537)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-16 02:43:39 +01:00
renovate[bot] ed751ab891 Update streetsidesoftware/cspell-action digest to ce1816e (#4531)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-14 21:14:50 +01:00
renovate[bot] 7d67a42cdf Update shivammathur/setup-php digest to eb7c497 (#4509)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-09 04:53:56 +01:00
renovate[bot] e174e3e274 Update github/codeql-action digest to 24c5418 (#4508)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-09 04:13:44 +01:00
renovate[bot] dcc76cbad1 Update actions/setup-node digest to 949feb2 (#4507)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-09 04:07:10 +01:00
renovate[bot] 92a3420cb7 Update release-drafter/release-drafter digest to 978bb0b (#4504)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-08 19:58:50 +01:00
renovate[bot] 1c33c71da0 Update actions/upload-artifact digest to cf430e0 (#4503)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-08 12:46:57 +01:00
renovate[bot]andAdam Daley 504ce9bd23 Update actions/download-artifact digest to 9000827 (#4502)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Adam Daley <admdly@users.noreply.github.com>
2026-10-08 12:37:09 +01:00
renovate[bot] f9b39ce2ef Update getsentry/action-release action to v3.7.1 (#4481) 2026-10-06 09:30:33 +01:00
Adam Daley ddb977925c Reconcile the release target when updating an existing release (#4454)
* Reconcile the release target when updating an existing release

A pre-existing draft release (for example one created by the Release Drafter job on the default branch) kept its original target_commitish, because --target was only passed on the create path. Reconcile it on the update path too, and require target_ref to be chosen explicitly instead of defaulting to main.

* Clean up comments in create-release.yml

Removed comments about reconciling target for releases.

* Refine target_ref description for better understanding

Clarify target_ref description in create-release.yml

* Refuse to attach an archive to a tag pointing at a different commit

An existing tag pins the release to a commit, and both --target on create and target_commitish on update are ignored once it exists. Verify the tag's peeled commit matches the checked-out ref before uploading so a re-run against a moved branch cannot publish an artifact that does not match the tag.

* Validate the release tag before uploading the archive to R2

The tag/commit check ran inside the GitHub release step, after the archive had already been mirrored to R2, so a mismatched tag could overwrite the version-specific download object before the job failed. Run it as a standalone step ahead of the R2 upload instead.
2026-10-03 07:52:52 +01:00
renovate[bot] 1e2f0426b1 Update release-drafter/release-drafter digest to 72967cd (#4447) 2026-10-02 22:46:29 +01:00
renovate[bot] 9c3629b5e6 Update release-drafter/release-drafter digest to c345907 2026-10-01 19:23:36 +00:00
Adam Daley 6415402ec2 Upgrade Tabler to 1.6 and adopt its admin components (#4412)
* Upgrade Tabler to 1.6 and adopt its admin components

* Fix spellcheck for Tabler integration notes and tests

* Build admin widget assets before Playwright tests

* Fix date input synchronization and clipboard fallback

* Refresh clipboard instances after mapping legacy targets

* Support Tabler clipboard attribute alias in fallback
2026-09-26 13:08:15 +01:00
renovate[bot] b8d191419c Update github/codeql-action digest to 2892aa5 2026-09-26 10:44:49 +00:00
renovate[bot] 4b9d321dea Update actions/github-script action to v9 (#4358)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-19 13:16:31 +01:00
Adam Daley ca970248f2 Set timeout on translation source check job (#4356) 2026-09-19 07:57:21 +01:00
Adam Daley c6992931bc Add open-source gettext extractor and translation source check (#4353)
* Add open-source gettext extractor and translation source check

Replaces the manual Poedit Pro step for regenerating messages.pot.
The extractor covers Twig |trans literals and PHP __trans /
__pluralTrans / exception keywords, mirroring the historical Poedit
runs (validated against the May 2026 messages.pot: only obsolete
fossils differ). Also adds an informational per-PR check reporting
msgid changes, as gettext matching is case-sensitive and casing-only
changes silently invalidate translations.

* Remove AI slop from extractor and workflow

Drop the unused function, unused parameters, unreachable branches,
restating comments and oversized docstring. No behavior change:
output verified byte-identical.

* Fix actions/github-script pin to a resolvable SHA

* Refresh i18n POT header and check label

* Rename translation workflow title

* Run translation source check on ubuntu-slim

* Ignore Python bytecode cache in scripts dir

* Address review: plural edge case and workflow injection

Skip __pluralTrans calls without a complete static plural instead
of emitting a misleading singular entry. Pass the pot diff to the
comment script via env to close the template-injection vector.

* Address review: one-to-one casing match and comment pagination

Consume each removed msgid at most once when pairing casing-only
changes, and paginate issue comments when locating the sticky
check comment.

* Address review: string-content calls, concat fragments, plural diff, credentials

Ignore keyword-like text inside PHP string/heredoc content, skip
concatenated first arguments instead of recording untranslatable
fragments (13 such fragments dropped from current output), report
plural changes across casing pairs, and set persist-credentials:
false with a non-failing comment step for fork PRs.

* Skip PHP string-content matches and fix heredoc terminators

Track string/heredoc spans during comment masking and ignore
keyword-like text inside them; also accept comma-terminated
flexible heredocs. Removes phantom refs and entries, keeps real
calls with correct line numbers (verified: timeago entries
intact, May-validation residuals all still excluded-path
fossils or untranslatable fragments).
2026-09-19 07:32:22 +01:00
renovate[bot] ccae9169e1 Update github/codeql-action digest to 1c5b675 2026-09-19 04:44:48 +00:00
renovate[bot] ec661f8778 Update docker/setup-buildx-action digest to f87e599 2026-09-17 07:05:48 +00:00
renovate[bot] 259eb7081f Update docker/setup-compose-action action to v2.4.0 (#4334) 2026-09-17 08:04:21 +01:00
renovate[bot] ca167a0a46 Update docker/setup-buildx-action digest to 594f3bf 2026-09-15 19:23:35 +00:00
renovate[bot] 6efc682544 Update docker/build-push-action digest to c3c9e26 2026-09-15 19:04:59 +00:00
renovate[bot] d0351f1b97 Update github/codeql-action digest to b96794f 2026-09-10 02:53:20 +00:00
renovate[bot] 80a3cdd478 Update streetsidesoftware/cspell-action digest to 6f3c77c 2026-09-05 00:19:59 +00:00
Adam Daley fabe3e3ee3 Mirror release archives to R2 for IPv6-only installs (#4255)
* Mirror release archives to R2 for IPv6-only installs (#2479)

github.com and api.github.com have no AAAA record, so FOSSBilling
installs on IPv6-only hosts (no NAT64) can check for updates via
api.fossbilling.net but can never actually download one - the
download_url it returns always points at a GitHub release asset.

The preview update channel already solves this: its download_url is
required to come from download.fossbilling.org, a Cloudflare R2
bucket that is confirmed reachable over IPv6. This extends the same
mirroring to stable releases:

- create-release.yml now uploads each release archive to R2 as well
  as the GitHub release, keyed by version
  (releases/{version}/FOSSBilling-{version}.zip) so old releases
  stay resolvable. The SHA-256 digest is computed once from the
  uploaded file and stored as R2 object metadata, so it can be read
  back without re-downloading and re-hashing.
- Update.php now trusts https://download.fossbilling.org/releases/
  as a download source, alongside the existing GitHub prefixes.

This only covers the in-repo half. api.fossbilling.net still needs
to start returning the download.fossbilling.org mirror URL (and its
digest) instead of the GitHub asset URL for the release branch -
that's tracked separately against that project.

* Remove inert --acl public-read from R2 uploads (#4256)

R2 doesn't implement S3 object-level ACLs; public access to
fossbilling-download objects is granted entirely at the bucket level
via the download.fossbilling.org custom-domain binding. The flag is
silently accepted but has no effect - confirmed against Cloudflare's
R2 docs and empirically via curl -6 against existing objects. Drop it
from both R2 upload steps (ci.yml preview upload, create-release.yml
release mirror) so it doesn't mislead someone into thinking it's what
makes these objects public.

Follow-up to a CodeRabbit comment on #4255, declined there as
out-of-scope since fixing only the new job would've been inconsistent
with the pre-existing pattern in ci.yml.
2026-08-30 20:01:13 +01:00
Adam Daley 441e9afba7 Pin 1Password CLI version in auto-cs-fix.yml (#4250)
The 'Load Secrets for FOSSBilling Bot' step omitted with.version,
installing the latest 1Password CLI on every scheduled run instead of
a pinned, tested version. Same class of finding CodeRabbit raised on
PR #4249's release-sentry.yml, which uses the same action.
2026-08-30 17:49:05 +01:00
Adam Daley f4f2e33a39 Report releases to Sentry in CI/CD (#4249)
* Report published releases to Sentry via sentry-cli

Adds a dedicated release-sentry.yml workflow, triggered on the GitHub
'release published' event (same trigger release-docker.yml already
uses), that creates/finalizes the matching Sentry release and
associates the commit range since the previous one (set_commits:
auto).

This intentionally does NOT live in create-release.yml: that workflow
defaults to creating a *draft* release (inputs.draft defaults to
true), and can be re-run multiple times against the same draft before
it's ever actually published. Reporting to Sentry from there would
mark a version 'released' before it's actually out, and would fire
again on every draft-update re-run. Triggering on 'release published'
instead captures the real moment a version becomes available -
whether that's a direct non-draft run or a draft published later by
hand - and only fires once.

This is separate from GitHub's repo-level commit-tracking integration
(which only feeds suspect-commit metadata generally) - nothing in the
existing setup was creating real Release objects with commit data for
0.8.1 onward, which is why every recent release shows no commits in
Sentry.

Needs a SENTRY_AUTH_TOKEN repo secret (project:releases + org:read
scopes) to actually run; until it's added the step just fails
harmlessly (continue-on-error: true).

* Report releases to Sentry as package@version for semver parsing

Sentry only parses a release identifier as semver (populating
major/minor/patch, enabling version-order regression detection and
release:latest) when it's in `package@version` form - a bare version
string like "0.8.6" doesn't qualify. Without it, Sentry falls back to
comparing release *creation dates* for things like 'resolved in next
release', which is unreliable for us specifically: an old release's
dateCreated is whenever some install still running it happens to send
its first event under the current Sentry project, not when the
version actually shipped (see the release-date backfill from earlier
this session - several were years off).

Adds SentryHelper::SENTRY_RELEASE_PACKAGE ('fossbilling') and reports
release as `fossbilling@{Version::VERSION}` going forward. Deliberately
not composer.json's "fossbilling/fossbilling" package name - Sentry
release identifiers can't contain a "/".

Updates release-sentry.yml's version input to match exactly
(fossbilling@<tag>), since the SDK's reported release string and what
CI associates commits/finalizes against have to agree or they won't
line up.

This only affects releases cut from here forward - already-shipped
0.6.x/0.7.x/0.8.x installs keep reporting their bare version string
forever, and there's no way to retroactively fix that.

* Load SENTRY_AUTH_TOKEN from 1Password instead of a raw repo secret

Matches auto-cs-fix.yml's existing pattern (1password/load-secrets-action,
reusing the same OP_SERVICE_ACCOUNT_TOKEN secret already configured for
that workflow) rather than asking for a new plaintext SENTRY_AUTH_TOKEN
GitHub secret. No new repo secret needed - just 1Password-side read access
to the vault item for the existing service account.

* Trim comments to match this repo's actual house style

Both files ended up with multi-paragraph inline explanations for
things that either duplicate each other, or belong in the PR
description instead of permanent code comments - out of step with
this repo's workflows (release-docker.yml has zero comments in 60
lines, create-release.yml has 1 in 279) and with SentryHelper.php's
own existing comment density elsewhere.

* Clarify Sentry auth token comment in workflow

* Address CodeRabbit findings: VM runner, pinned op CLI, release input

- runs-on: ubuntu-latest instead of ubuntu-slim - getsentry/action-release
  runs as a docker:// container action on Linux, and ubuntu-slim can't run
  a Docker daemon (unprivileged, confirmed against GitHub's own runner docs).
  This would very likely have failed on first real use.
- Pin 1password/load-secrets-action's CLI version instead of installing
  latest on every run (matches the currently-installed 2.39.0).
- Use the release: input instead of version:, which action-release marks
  deprecated as of this pinned SHA.

Declined a fourth suggestion (enforce release-version equality against
FOSSBilling\Version::VERSION in create-release.yml): Version::VERSION is
written FROM inputs.version during the Docker build (regex substitution
that hard-fails if it doesn't apply exactly once), not sourced
independently, so it can't diverge - see reply on the PR thread.
2026-08-30 17:39:22 +01:00
renovate[bot] b6cdf436a0 Update github/codeql-action digest to cdf488f 2026-08-27 02:28:54 +00:00
Adam Daley 5f6397cb12 Fix and harden the Code Quality & Styling automation (#4206)
* 🎨 Apply pending Rector/PHP-CS-Fixer fixes

Drift left over from the auto-cs-fix.yml run that failed to open its
PR due to an expired BOT_TOKEN.

* 🐛 Fix code quality workflow and add PR-level style check

- Rotate the sweep's push credential from BOT_TOKEN (expired) to
  FOSSBILLING_BOT_TOKEN, a fresh fine-grained PAT scoped to just this
  repo (contents, pull-requests, issues: read/write).
- Factor the shared Rector/PHP-CS-Fixer setup out of auto-cs-fix.yml
  into a local composite action, .github/actions/php-quality-setup.
- Add code-quality-check.yml: a read-only dry-run check that runs on
  every pull request, including forks, scoped to just the files each
  PR changes so pre-existing drift on main can't fail an unrelated
  PR. Complements the scheduled sweep, which now only needs to catch
  drift from rule/tool-version changes on code no open PR touches.

* 🎨 Replace peter-evans/create-pull-request with gh CLI

Removes the third-party Action dependency for opening the sweep's PR
in favor of the officially-maintained gh CLI, which ships preinstalled
on GitHub-hosted runners:

- gh auth setup-git wires GH_TOKEN into git's credential helper, so
  plain git push/fetch authenticate without a hand-rolled
  http.extraheader (what silently broke with the old BOT_TOKEN).
- chore/cs-fix is fully regenerated every run, so there's no need to
  diff against existing remote content — force-with-lease push plus
  gh pr list/create covers create-or-update.
- Also more portable: the same script runs unchanged outside GitHub
  Actions' action-invocation model (other CI, cron, a terminal),
  whereas a third-party Action cannot.
- Top-level permissions trimmed to contents: read — nothing in the
  job uses the implicit GITHUB_TOKEN anymore.

* 🔒 Pin 1password/load-secrets-action to v5.0.1 by SHA

Was floating on the mutable @v4 tag, inconsistent with every other
third-party action in this repo (all pinned by commit SHA), and a
version behind — v5.0.1 is current as of last week and includes
1Password's own CI hardening. No breaking changes for our usage
(OP_SERVICE_ACCOUNT_TOKEN path is untouched; v5.0.0 only adds an
alternative OIDC auth method).

* 🎨 Remove unused create_pr operation output

Set in both branches but never read — the job summary only uses
.outputs.url, and the same created-vs-updated info is already in the
step's own log output.

* 🐛 Fix two Rector rules that generate code breaking Pest

CI on PR #4206 caught these — I'd only run php -l (syntax check) on
the earlier drift-cleanup commit, not the actual test suite, and both
slipped through:

- AddArrowFunctionReturnTypeRector typed Pest expect()-chain closures
  as their IDE-only @mixin stub (Pest\Mixins\Expectation) instead of
  the real runtime class (Pest\Expectation) — throws a TypeError.
- ArrowFunctionDelegatingCallToFirstClassCallableRector converted a
  Pest ->with() dataset closure to a first-class callable reference,
  which breaks Pest's Closure::bindTo() lazy-evaluation step (no scope
  to rebind on a closure derived from a plain function).

Both only misfire against Pest's dynamic patterns in tests/, so
they're skipped there specifically rather than repo-wide — src/ keeps
the benefit. Reverts the two bad transformations and re-verifies with
the full Pest suite this time, not just php -l.

* 🎨 Apply Rector fixes for drift introduced by #4205

RecastingRemovalRector: three redundant (string) casts, plus one
PHP 8.3 typed-const/literal-return-type modernization in
CacheFactory.php — all from files #4205 touched after this branch
forked from main.

Verified with the full suite this time (2812 tests, 10979 assertions)
and PHPStan, not just php -l.

* 🎨 Fix import order in rector.php

Caught by the new PR check itself — it passes rector.php as one of
the changed files, so PHP-CS-Fixer processes it directly (path-mode
override), unlike the scheduled sweep whose Finder never scans
repo-root config files at all.

* 🔒 Fix script-injection risk and stale fetch ref from CodeRabbit review

- code-quality-check.yml: the changed-file list was interpolated via
  ${{ steps.changed_files.outputs.files }} directly into a run: script.
  That's literal text substitution before bash parses anything, so a
  PHP filename containing shell metacharacters (or just a space) could
  break argument parsing or execute as a command. Fixed by writing the
  NUL-delimited path list to a file and reading it back into a real
  bash array with mapfile in every step that needs it — only a plain
  boolean (has_php_files) now crosses the ${{ }} boundary. Verified:
  a space-containing filename was silently split into two broken
  arguments under the old design; the array-based version preserves
  it as one element.
- auto-cs-fix.yml: pin the fetch to update the actual remote-tracking
  ref (refs/remotes/origin/chore/cs-fix), not just FETCH_HEAD, so
  --force-with-lease always has a real baseline to compare against.

* 🔒 Add option-terminator before changed-file paths

A filename beginning with '-' would otherwise be parsed as a Rector/
PHP-CS-Fixer CLI option rather than a path. Not currently reachable
given rector.php/.php-cs-fixer.dist.php scope to src/ and tests/ (a
repo-relative diff path always has that prefix), but zero-cost to
harden regardless. Verified the composed composer script -- ... -- ...
invocation forwards the second terminator correctly.

* 🎨 Apply Rector/CS-Fixer fixes for drift introduced by #4204

readonly on Registrar_Rdap::$httpClient (verified: only ever assigned
in the constructor), PHP 8.3 typed consts, redundant @param mixed
removal, pre-increment style. Verified with the full suite (2854
tests, 11055 assertions) and PHPStan.
2026-08-25 22:16:58 +01:00
Adam Daley aa0f776160 Migrate E2E suite from Cypress to Playwright (#4186)
* Migrate E2E suite from Cypress to Playwright

* Address review feedback for Playwright migration

Use Symfony Filesystem::mkdir() for the test uploads directory instead of
suppressed native mkdir, and tolerate an optional trailing slash in the
admin smoke test URL assertions.
2026-08-23 22:23:06 +01:00
renovate[bot] d9a4879973 Update github/codeql-action digest to db488dd 2026-08-22 00:31:14 +00:00
renovate[bot] 2ae1622d2d Update docker/setup-buildx-action digest to 37fe631 2026-08-20 00:31:30 +00:00
renovate[bot] 8a41f095d6 Update streetsidesoftware/cspell-action digest to e0668cf 2026-08-16 01:25:30 +00:00
renovate[bot] a66bfc079d Update streetsidesoftware/cspell-action action to v9 (#4168) 2026-08-15 19:24:46 +01:00
Adam Daley 791c54d13c Update CI to use vars for registry config (#4163) 2026-08-15 07:53:31 +01:00
renovate[bot] 4eceb56e96 Update github/codeql-action digest to ff2f1c6 2026-08-15 01:06:35 +00:00
Adam Daley 28f342aa20 Add preview archive metadata to CI upload (#4157)
* Add preview archive metadata to CI upload

* Fix preview artifact upload in CI

* Add short SHA to preview artifact name

* Version preview ZIP artifacts by commit

* Simplify preview artifact staging

* Fix short SHA export in CI preview step
2026-08-13 17:28:29 +01:00
Adam Daley d9d9ff4ff9 Update release-drafter label rules (#4153) 2026-08-13 10:20:27 +01:00
renovate[bot] dbb8f8cd1d Update github/codeql-action digest to 5595cca 2026-08-05 00:39:03 +00:00
renovate[bot] 2507bb2992 Update github/codeql-action digest to d1ba80a 2026-08-03 12:04:26 +00:00
renovate[bot] 9f706f748f Update github/codeql-action digest to f205ea1 2026-07-30 21:36:22 +00:00
renovate[bot] 64701fe9da Update release-drafter/release-drafter digest to 34d8067 2026-07-30 04:36:56 +00:00
renovate[bot] 22b4e21b38 Update docker/login-action digest to dbcb813 2026-07-30 01:55:09 +00:00
renovate[bot] cf3f31cdb8 Update docker/login-action digest to 371161b 2026-07-29 01:37:06 +00:00
renovate[bot] 858d3e1c58 Update docker/login-action digest to abd2ef4 2026-07-25 02:30:10 +00:00
renovate[bot] 58b79568d7 Update docker/login-action digest to 06fb636 2026-07-23 19:07:10 +00:00
renovate[bot] cc86628c78 Update github/codeql-action digest to e4fba86 2026-07-23 02:53:25 +00:00
renovate[bot] 7558d636dc Update github/codeql-action digest to e064762 2026-07-22 02:28:53 +00:00