Skip to content

Prepare AffilStack for Google's least-privilege scope review - #14

Merged
nwaezedavid merged 15 commits into
affilstack-appfrom
cowork/20261030-083707-affilstack-fixes
Nov 5, 2026
Merged

nwaezedavid merged 15 commits into
affilstack-appfrom
cowork/20261030-083707-affilstack-fixes

Conversation

@nwaezedavid

Copy link
Copy Markdown
Owner

Pushed from Claude Cowork bundle affilstack-fixes.bundle.

Commits:

  • Add the new features to the marketing site
  • List marketplace add-ons in the sitemap; document the developer subdomain and optional gateways in .env.example
  • Only send add-on buyers back to the Connect screen after paying
  • Build on PHP 8.4 and 8.5, and protect AffilStack from PHP2Shell
  • Accept host-backported PHP2Shell fixes by PHP build date
  • Record the Hostinger deploy target
  • Never serve release packages, backups or logs from the public folder
  • Record the release-folder layout used on Hostinger
  • Serve feature demo videos with their real types
  • Fix the Feature demos admin page 500 on Hostinger
  • Request the Site Verification scope for Search Console setup
  • Print only the code in search engine verification tags
  • Send "{}" instead of "[]" on bodiless Google and PayPal calls
  • Submit the Bing sitemap through SubmitFeed
  • Prepare AffilStack for Google's least-privilege scope review

claude added 15 commits October 22, 2026 20:35
Feature pages, homepage cards, help answers, menu links and pricing
allowances for WordPress publishing, affiliate network connections,
AffilStack in your language and the add-on marketplace, with real
screenshots. A migration ships them to existing sites without touching
admin edits. Plans now include WordPress sites and network connections,
demo data covers the new features, and dependencies get security patches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZBiaiMwi6BCi8vmwJFScW
…main and optional gateways in .env.example

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZBiaiMwi6BCi8vmwJFScW
- composer.json requires PHP ^8.4 (the locked Symfony 8 packages already
  needed it, which is why the PHP 8.3 build failed); CI tests PHP 8.4 and
  8.5, builds the front end first, and runs on affilstack-app pushes.
  Dependabot now also proposes Composer and npm security updates.
- Tom's daily scan checks the PHP the website and the cron run on against
  the PHP2Shell fixes (8.4.27 / 8.5.12) and php.net's newest security
  release, plus risky php.ini settings; new critical/high findings email
  the admins, cleared ones close themselves, and the admin panel shows a
  red bar while the website's PHP is unpatched. security:check-php fails a
  deploy on an unpatched PHP.
- Web-shell defences: uploads carrying PHP (names, double extensions,
  .htaccess, code hidden in images) are refused on every form and API
  route; only index.php may run as PHP; requests over 40 MB stop at the
  web server; public/.user.ini turns off session upload progress and caps
  request size; Tom looks for PHP files in public and upload folders.
- Manual GitHub sync runs in the queue, so the website no longer needs
  proc_open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZBiaiMwi6BCi8vmwJFScW
Hostinger backports security fixes into PHP 8.4.26 / 8.5.11 without
changing the version number. The PHP check now reads the binary's build
date: a build dated on or after the fix's release is reported as a low
note to confirm with the host instead of critical, and php.net's newer
releases are judged the same way. Build dates are shown by
security:check-php and recorded for the website's PHP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZBiaiMwi6BCi8vmwJFScW
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZBiaiMwi6BCi8vmwJFScW
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZBiaiMwi6BCi8vmwJFScW
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZBiaiMwi6BCi8vmwJFScW
The page had 37 inline video upload fields, and each one sent its own
Livewire request as the page opened. Hostinger refuses MySQL connections
past about 20 at once per user, so most of those requests failed with
"Operation not permitted" and the page returned a 500.

Each card now has an "Upload my own video" button that opens a modal
with the upload field, plus "Remove my video". Uploads save straight
away and delete the file they replace. Opening the page now sends one
request instead of 37.

Also keeps storage/framework/php-runtime.json out of git.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZBiaiMwi6BCi8vmwJFScW
"Verify Search Console" failed with 403 ACCESS_TOKEN_SCOPE_INSUFFICIENT:
the Site Verification API (which issues and checks the homepage meta
tag) isn't covered by the webmasters scope. The Site Analytics connection
now also asks for siteverification.verify_only, the narrowest scope that
allows getToken and webResource.insert.

A connection made before this change shows a plain "Reconnect with
Google" message instead of Google's raw error. The built-in Site
Analytics guide lists the new scope.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZBiaiMwi6BCi8vmwJFScW
Google's Site Verification API returns the whole <meta> tag as the
token, and AffilStack stored and printed it inside content="", so the
homepage carried a broken google-site-verification tag and Google could
not confirm ownership.

SiteVerificationCode::normalize() keeps only the code. It runs when the
token comes back from Google, when SEO settings and Bing settings are
saved, and when the head tags are printed, which also repairs a value
that was already saved. The "couldn't confirm" message now includes
Google's own reason.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZBiaiMwi6BCi8vmwJFScW
Laravel's HTTP client sends an empty JSON array ("[]") when put() or
post() get no data. Google refuses that ("Root element must be a
message"), so adding the verified site to Search Console failed right
after verification succeeded, and the sitemap submit failed silently.
Both Search Console PUTs now send an empty JSON object.

A refused sitemap no longer goes unnoticed: the site still counts as
verified, and the message gives Google's reason and what to do.

PayPal's order capture made the same bodiless POST; it now sends "{}"
too, so PayPal can't reject a payment capture as malformed JSON.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZBiaiMwi6BCi8vmwJFScW
Bing's Webmaster API has no SubmitSitemap method, so every sitemap
submission got an empty 404 and the page said "Sitemap submission
failed". The method is SubmitFeed, which takes the sitemap as feedUrl.
The site address is now sent exactly as Bing lists it, and a refusal
shows Bing's own message plus the manual fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZBiaiMwi6BCi8vmwJFScW
Google asked for a new demo video and proof that every requested scope is
needed. Four changes make that possible:

- Site Analytics no longer requests tagmanager.publish. AffilStack only
  creates the container and never publishes versions, so the scope was
  unused.
- Site Analytics can use its own Google Cloud project ("Use a separate
  Google project" on the page). Analytics, Search Console and Tag Manager
  permissions are only for the site owner, so they stay out of the
  customer app Google verifies. Switching projects clears the old tokens
  and keeps the GA4, Search Console and Tag Manager details; disconnecting
  keeps the separate client.
- Site > Google Login has a "While Google reviews Gmail and YouTube"
  section. With the limit on, only listed test accounts and admins see
  Connect Gmail and Connect YouTube, as Google asks for unverified scopes.
  Testers can also publish to YouTube before the audit status is
  Approved, so the reviewer sees the upload arrive.
- Users > "Give a plan for free" starts a plan without payment for a
  review or test account: monthly credits, a verified email, and an end
  date with no renewal reminders. It refuses to touch a paid plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZBiaiMwi6BCi8vmwJFScW
@nwaezedavid
nwaezedavid enabled auto-merge October 30, 2026 07:37
@nwaezedavid
nwaezedavid merged commit 24fe6e6 into affilstack-app Nov 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants