- Rubocop Style/RedundantRegexpEscape: remove unnecessary \- in two
character classes in FULL_EMAIL_REGEXP (user.rb:59)
- Brakeman LinkToHref XSS: add fingerprint to brakeman.ignore — the
filter_path guard (start_with?('/')) prevents javascript: and
absolute-URL attacks; Brakeman still tracks params[:path] taint
through the conditional assignment
- RSpec install: switch pdfium binary source from the deleted
docusealco/pdfium-binaries to bblanchon/pdfium-binaries (same
tarball layout: lib/libpdfium.so)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Patch release covering the security findings from the repo's first
CodeQL scan against 1.3.0:
- Sanitise params[:path] before it flows into form action / link href
in submissions_filters/_filter_modal (reflected XSS).
- Slice required_params to email/phone before passing to find_by! /
find_or_initialize_by in start_form_controller (column-name
injection via template-owner-controlled link_form_fields preference).
- Rewrite FULL_EMAIL_REGEXP local-part to remove the nested quantifier
(ReDoS).
- Replace the Bearer-token regex in mcp_controller with a string
prefix check (polynomial ReDoS).
- Swap Math.random()-based attachment UUIDs for crypto.randomUUID()
in the submission-form Vue dropzone / signature / initials steps.
- Add a workflow-level permissions: read-all block to ci.yml.
See CHANGELOG.md [1.3.1] for the full per-alert breakdown and the
list of CodeQL findings that are false positives in context.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous lint fix swapped a `<% ... %>` block-opener style but
left a multi-line hash literal and multi-line `case` expression inside
the same ERB tag, which tripped Layout/FirstHashElementIndentation,
Layout/IndentationConsistency, and the closing-newline-before-`%>`
rule.
Reshape: each assignment lives in its own single-line `<% %>` tag, and
the per-provider sending-number lookup is a plain hash dispatch rather
than a multi-line case. Same runtime behaviour; lint-clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Rubocop:
- lib/sms/providers/{signalwire,twilio}.rb: collapse the
Net::HTTPSuccess success-path `if` into modifier form
(Style/IfUnlessModifier).
- lib/sms/providers/signalwire.rb: `delete_suffix('/')` instead of
`sub(%r{/\z}, '')` (Performance/DeleteSuffix).
- app/controllers/sms_settings_controller.rb: move SECRET_KEYS to
the top of the class so it isn't sandwiched under `private`
(Lint/UselessConstantScoping). Ruby constants aren't actually
privatised by a preceding `private` keyword anyway.
Erblint:
- app/views/sms_settings/index.html.erb: replace `javascript_tag do`
with a raw `<script nonce=...>` block so erblint's
AvoidUsingJavascriptTag rule is satisfied. CSP nonce comes from
Rails' content_security_policy_nonce helper, same source as before.
- Inline the ERB block-opener so Ruby doesn't see a leading empty
line (Layout/LeadingEmptyLines).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Features list now mentions Twilio, VoIP.ms, and SignalWire alongside
BulkVS. Docker pull example and Releases section point at 1.3.0.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CHANGELOG entry for the SMS branch merge (3b1003eb). .version bumped
to 1.3.0 so the in-app footer + OCI image label reflect the new
release.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Brings the three new SMS providers (Twilio, VoIP.ms, SignalWire) up
alongside the existing BulkVS integration. Per-account credentials
live in the encrypted sms_configs hash, namespaced by provider; the
provider select on /settings/sms drives a per-provider field block.
Clean merge — no conflicts with the post-DocuSeal-3.0.0 master.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CHANGELOG entry for the merge of upstream tag 3.0.0 plus the
rebrand-sync / rebrand-check tooling added in 6b652f8a. .version
bumped to 1.2.0 so the in-app footer + image label reflect the new
release.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
First exercise of the bin/rebrand-sync workflow. Upstream 3.0.0
(merge-base 528a1216, 15 commits) brought:
Auto-merged cleanly (no conflict):
- New controllers/routes: submissions_resend_email (route added by
hand to config/routes.rb since fork's routes diverged elsewhere),
template_documents, templates_clone_and_replace, templates_folders,
templates_restore, templates_versions, submissions_unarchive
- PDF optimizations and signing-form completion-button refactor
(e378025a, 04129ded, 7fe56941)
- Percent formatting (99ca0136), area-box clamping (41604008),
validation message rephrasings (abd498dd)
Conflicts resolved (rerere now caches these for next sync):
- "take ours" for files where the fork stripped freemium gates
(Plans/Console/Upgrade, ENTERPRISE_PATHS, multitenant guards on
esign default sig, reminder durations, decline/delegate toggles,
BCC and send-on-completion, Pro upsell placeholders for SMS/SSO/
bulk-send/payment/conditions/formula/phone-field)
- "take ours" for per-account branding helpers
(Wabosign.branded_product_name vs Wabosign.product_name) across
mailers, MFA, MCP, audit-trail PDFs, page titles
- "take ours" for fork brand URLs (sign.wabo.cc, Wabosign::PRODUCT_URL,
Wabosign::GITHUB_URL) over upstream's hardcoded wabosign.com
- "take ours" for the webhook User-Agent ("WaboSign Webhook" not
"WaboSign.com Webhook") and X-Wabosign-Signature header
- "take theirs" for submitters_send_email's defensive authorize!(:update)
(security improvement from upstream commit e52830c9)
- Hybrid resolution in lib/send_webhook_request.rb — keep fork's
USER_AGENT, take upstream's "don't override custom webhook header"
blank-check (a7891f89)
- 22 "deleted by us" files (Pro upsell controllers/views, removed
docs/api/*, deleted newsletter feature) confirmed deleted
Known gaps to fix as follow-ups:
- config/locales/i18n.yml — taken ours wholesale; missing upstream's
three new resend-email keys (re_send_emails,
are_you_sure_you_want_to_re_send_email_to_n_recipients,
emails_have_been_sent_to_n_recipients) across all 14 languages.
English fallback works for those strings until translated.
- Gemfile.lock — taken ours; needs `bundle install` to regenerate
with upstream's gem updates from 37d4a8e8.
- yarn.lock — same; needs `yarn install`.
- bin/rebrand-sync — the `\bdocuseal_` rule misses `_docuseal_` inside
identifiers (e.g. `unlock_with_docuseal_pro` i18n keys). Widening
to `docuseal_` (no leading word boundary) would catch those. Tracked
as a script refinement before the next sync.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Output of bin/rebrand-sync against the upstream 3.0.0 tree. Renames
lib/docuseal.rb → lib/wabosign.rb, rewrites the Docuseal/DocuSeal
identifiers to Wabosign/WaboSign across controllers, jobs, mailers,
views, JS/Vue, locales, specs, and infrastructure (Dockerfile,
docker-compose, CI workflows, env-file path, AATL cert name).
This commit is the sync branch's contribution to the merge — it does
NOT carry the fork's features (SSO, SMS, per-account branding, etc.)
or the bin/rebrand-* scripts themselves; those arrive via the
subsequent merge into master.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a deterministic rebrand sweep so each upstream sync is a scripted
transformation rather than a manual sweep:
- bin/rebrand-sync — idempotent Ruby script that rewrites DocuSeal →
WaboSign tokens across the tree (Ruby module, AATL cert name, DB
names, Docker user, registry/repo URLs, DOM-ID/localStorage prefix,
daisyUI theme name, hardcoded UI strings). Sentinel-protects AGPL
§7(b) attribution phrases, SDK custom-element identifiers, the
@docuseal/* npm packages, and the docusealco/{fields-detection,
pdfium-binaries,turbo} binary URLs. Deny-lists NOTICE, LICENSE_*,
README, the AGPL attribution partials, calculator.js's DocuSeal LLC
copyright, lib/wabosign.rb's UPSTREAM constants, and the
docuseal_aatl migration that searches by the legacy name.
- bin/rebrand-check — fails CI when an unintended DocuSeal reference
survives in the tree. Wired in as the new `Rebrand check` job in
.github/workflows/ci.yml.
- REBRANDING.md gains a "Sync workflow" section documenting the
per-sync steps, rerere setup, and how to keep the two scripts'
allow/preserve lists in sync.
- .gitattributes marks Gemfile.lock and yarn.lock as -merge — they get
regenerated post-merge rather than diffed.
- Latent rebrand leftovers fixed: public/service-worker.js no longer
logs "DocuSeal App installed/activated"; .dockerignore and
.gitignore now ignore /wabosign (the actual runtime data dir mount)
rather than the stale /docuseal path.
Strategy detail lives at .claude/plans/come-up-with-a-foamy-flask.md.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds three new selectable providers behind the existing
Sms.send_message interface. Per-account credentials are namespaced in
the encrypted sms_configs hash (twilio_*, voipms_*, signalwire_*) so
existing BulkVS configs keep working unchanged.
- lib/sms.rb: dispatch via per-provider classes and delegate the
"is this configured" check to each provider, replacing the BulkVS-only
hardcoded gate in enabled_for?.
- lib/sms/providers/twilio.rb: form-encoded POST to the Messages API,
Basic Auth with SID:Token, treats 201-with-error_code as failure.
- lib/sms/providers/voipms.rb: GET with query-string auth, treats
status != "success" as failure even on HTTP 200, enforces the API's
160-byte hard cap up front.
- lib/sms/providers/signalwire.rb: Twilio-shaped client targeting the
per-account Space URL host; strips https:// and trailing / from the
user-supplied space URL.
- app/controllers/sms_settings_controller.rb: extend the
preserve-secret-on-blank-edit pattern to all four providers' password
fields via a SECRET_KEYS array.
- app/views/sms_settings/index.html.erb: dynamic provider select sourced
from Sms::SUPPORTED_PROVIDERS with per-provider field blocks toggled by
a nonce'd inline script (the app's CSP requires nonces on inline JS).
- SMS.md: new "Configuring …" sections for each provider, wire-format
quick-reference table, and updated extension/code-map sections.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Account admins can now replace "WaboSign" in the UI, emails, audit-trail
PDFs, and authenticator-app issuer with their own product name. The
brand override is stored as an AccountConfig row (brand_name key),
managed from /settings/personalization above the logo upload.
Resolution flows through Wabosign.branded_product_name(account = nil):
1. account&.brand_name if a record is passed
2. else the deployment's oldest non-archived account's brand_name
(so anonymous surfaces like the landing page, PWA manifest, and
og:title get the operator's brand on single-tenant installs)
3. else Wabosign::PRODUCT_NAME ("WaboSign")
AGPL §7(b) DocuSeal attribution stays untouched:
- _powered_by.html.erb second line keeps Wabosign::UPSTREAM_NAME
- _email_attribution.html.erb second paragraph keeps it
- completed.vue keeps its hardcoded DocuSeal link
The Wabosign::UPSTREAM_NAME and UPSTREAM_URL constants stay constants —
they are never overridable.
Swapped 41 direct Wabosign.product_name callers to pass the most-local
account in scope (current_account, @template.account,
@submitter.submission.account, submission.account, or nil for chrome
without account context). Mailers' default `from:` is now a lambda that
reads @current_account per message. SIGN_REASON constant in
generate_result_attachments became sign_reason_template(account) so
PDF signature reasons reflect the brand.
The two i18n keys actually rendered with literal "WaboSign"
(welcome_to_wabosign in templates_dashboard, connect_to_wabosign_mcp
in mcp_settings) are parameterized to %{product_name} across the 7
locales that defined them. The other ~9 WaboSign-branded i18n keys
are unreferenced dead code from the Pro paywall and stay as-is.
Specs:
spec/models/account_spec.rb (new) — Account#brand_name
spec/lib/wabosign_spec.rb (new) — branded_product_name precedence
spec/requests/personalization_settings_spec.rb (new) — end-to-end
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- actions/checkout@v3 -> @v4 in docker.yml
- actions/setup-node@v1 -> @v4 in ci.yml (both jobs that use it)
- Replace deprecated `::set-output` with $GITHUB_OUTPUT in the
ESLint yarn-cache-dir step
The remaining Node 20 deprecation warnings on actions/cache@v4,
actions/checkout@v4, and the docker/* actions will resolve once
upstream ships Node 24 builds; not blocking, the runtime won't
flip until 2026-06.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
erblint's autocorrect on the prior commit stripped the opening
<% tag from the variable-assignment block in
app/views/shared/_account_logo.html.erb, leaving plain Ruby code as
literal HTML and a NameError on every render. The "Failure/Error:
<% if acc&.logo&.attached? %>" cascade in CI was 40+ specs hitting
this partial via the navbar / start_form / submit_form / share-link
QR / submission show paths. Restoring the proper <% ... %> tag.
Also drop the now-redundant `# rubocop:disable Rails/Exit` comments
in spec/rails_helper.rb (CI's rubocop-rails doesn't flag those
lines) and add the same path to .rubocop.yml's Rails/Exit Exclude
so the project's local rubocop agrees.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Previously CI had never run on the wabolabs/wabosign fork (Actions
gated until owner consent). Now that the gate is lifted, run rubocop /
erblint / brakeman / rspec against current master uncovered backlog:
- rubocop: 97 auto-corrected across the WaboSign-fork files (account
logo, SMS, SSO, ability specs, role auth specs, omniauth callbacks).
Remaining 8 fixed by hand:
* lib/wabosign.rb chained map collapsed to filter_map; `hd` param
renamed to `hosted_domain` (Naming/MethodParameterName)
* app/models/user.rb default_sso_account split for line length +
SafeNavigation
* spec/rails_helper.rb abort calls marked `# rubocop:disable
Rails/Exit` (upstream pattern, intentional)
* spec/requests/users/omniauth_callbacks_spec.rb let! used for
side-effect-only setup -> moved into before blocks
- erblint: 21 auto-corrected (mostly Style/StringLiterals from a
sed substitution that picked double quotes) + a missing
autocomplete attribute added to the SMS test-message input.
- brakeman: clean. Removed one obsolete ignore entry (was for the
deleted enquiries controller) and added one new ignore for the
MCP-settings token preview (HighlightCode returns escaped HTML).
- rspec: dashboard "shows the list of templates" was flaky because
other_template's Faker::Book.title could randomly collide with one
of the 5 in-account templates. Pin the name to a unique suffix.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>