diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 2b85e90..eca9d9c 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -15,6 +15,7 @@ {"_type":"issue","id":"hc-5ix.4","title":"Session data model: option-backed in-progress healthcheck record","description":"One in-progress session per site at a time. Stored in a custom option (or a CPT — pick during implementation). Shape: id, started_at, finished_at, technician_id, site_url_snapshot, per_step_state { status: not_started|in_progress|done|skipped|blocked|n_a, notes, completed_at }. Designed so phase-3 automation can attach structured findings later.","notes":"Built in phase-1 scaffold; passing lint + WP-eval end-to-end smoke test on testsite.","status":"closed","priority":1,"issue_type":"task","owner":"steve@hanlon.co.uk","created_at":"2026-06-11T14:36:11Z","created_by":"Steve Hanlon","updated_at":"2026-06-11T14:49:27Z","started_at":"2026-06-11T14:41:27Z","closed_at":"2026-06-11T14:49:27Z","labels":["phase-1"],"dependencies":[{"issue_id":"hc-5ix.4","depends_on_id":"hc-5ix","type":"parent-child","created_at":"2026-06-11T15:36:11Z","created_by":"Steve Hanlon","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-5ix.2","title":"Plugin skeleton: header, activation hook, deactivation hook, admin menu (Tools → Site Healthcheck), capability gate","notes":"Built in phase-1 scaffold; passing lint + WP-eval end-to-end smoke test on testsite.","status":"closed","priority":1,"issue_type":"task","owner":"steve@hanlon.co.uk","created_at":"2026-06-11T14:36:10Z","created_by":"Steve Hanlon","updated_at":"2026-06-11T14:49:26Z","started_at":"2026-06-11T14:41:27Z","closed_at":"2026-06-11T14:49:26Z","labels":["phase-1"],"dependencies":[{"issue_id":"hc-5ix.2","depends_on_id":"hc-5ix","type":"parent-child","created_at":"2026-06-11T15:36:09Z","created_by":"Steve Hanlon","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-5ix.1","title":"Bootstrap: trigger install of wp-site-recovery plugin as step 0","description":"Healthcheck plugin should check on activation if site-recovery is installed; if not, fetch and install from a known URL/ZIP and activate it. Block stepper from starting until recovery is in place.","notes":"Detection half done (status panel + manual link). Auto-install of recovery plugin from a private URL is the wp-site-recovery side of hc-5ix.27 — closing this as 'detection complete'.","status":"closed","priority":1,"issue_type":"task","owner":"steve@hanlon.co.uk","created_at":"2026-06-11T11:26:40Z","created_by":"Steve Hanlon","updated_at":"2026-06-11T15:03:02Z","closed_at":"2026-06-11T15:03:02Z","labels":["phase-1"],"dependencies":[{"issue_id":"hc-5ix.1","depends_on_id":"hc-5ix","type":"parent-child","created_at":"2026-06-11T12:26:39Z","created_by":"Steve Hanlon","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"hc-adg","title":"Recovery installer pulls unpinned 'latest' from Gitea + auto-activates without signature check","description":"`recovery-installer.php` (`resolve_latest_ref()` L67-92, install L148) fetches the recovery plugin from Gitea using an unpinned reference (releases → tags → `main` branch archive fallback), then feeds the downloaded ZIP straight to WP's `Plugin_Upgrader::install()` which activates the code.\n\nTrust anchor is Gitea repo integrity: whoever controls the recovery repo (or a leaked Gitea deploy token) controls what runs on every install at next tech click.\n\nTLS verification is on (default `wp_remote_get` behaviour, not disabled anywhere), so MITM is out of scope — but supply-chain compromise of the Gitea repo is not.\n\nNote: this is the same trust model as the new PUC auto-update flow (hc-8gb) — so it's not a new risk introduced by that change, but it's worth naming and mitigating in the same pass.","design":"Options:\n\n**a) Pin to signed tags only.** Require the recovery installer to reject anything that isn't a signed tag (verify via Gitea API's tag object). Only works if we start GPG-signing releases.\n\n**b) Verify a SHA-256 hash from a second source.** Ship an expected-hash constant in the plugin (updated at release time). Installer fetches ZIP + verifies hash before install. Simple, effective, but couples plugin releases to recovery releases.\n\n**c) Detached signature file alongside the ZIP.** e.g. `recovery-1.2.3.zip.sig` verified against a public key baked into the healthcheck plugin. Best long-term option, most setup.\n\n**d) Reduce blast radius via read-only, single-repo Gitea tokens.** Doesn't stop repo compromise but shrinks the credential footprint.\n\nRecommendation: start with **(b)** — quick win. Consider **(c)** if we ever distribute recovery outside the internal network.","acceptance_criteria":"- [ ] Recovery installer refuses to install a ZIP whose SHA-256 doesn't match an expected value shipped in the plugin (or a similar integrity check)\n- [ ] Recovery repo Gitea token is read-only + scoped to just that repo\n- [ ] README documents the release-integrity flow","notes":"Reported in 2026-07-16 security review. Flagged as risk #2 of 3.\n\nRelated: hc-8gb introduced PUC-based auto-updates for THIS plugin with the same trust model. Any signing/hashing scheme we build for recovery should be reusable for the healthcheck plugin's own updates.","status":"open","priority":2,"issue_type":"bug","owner":"steve@hanlon.co.uk","created_at":"2026-07-16T10:14:40Z","created_by":"Steve Hanlon","updated_at":"2026-07-16T10:14:40Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-gp3","title":"Harden API key handling — remove settings-page echo, add DB encryption or force constants","description":"Central-server API key is currently exposed in two ways that widen the blast radius of a compromise:\n\n1. `admin-page.php:749` renders the key back into an `\u003cinput type=\"password\"\u003e` on the settings page — trivially unmasked via DOM inspector by any user with `manage_options`.\n2. When set via the settings UI (not a wp-config constant), the key is stored plaintext in `wp_options` under `att_hc_api_key` — readable by any user or process with DB access.\n\nBecause the same key is shared across every WP install that talks to the central server, a leak from one site gives read/write on every other site's healthcheck history.","design":"Options (pick one or combine):\n\n**a) Never render the key back into the input.** Show only a masked placeholder like `••••••••abc3` (last 4 chars) with a 'change' button that swaps in an empty input. Won't help against DB reads but blocks the easiest exfiltration path.\n\n**b) Force wp-config constants only.** Delete the settings-page input for the key entirely; require `ATT_HC_API_KEY` in `wp-config.php`. Simple, most secure, but loses the managed-host convenience the original design called out (`class-att-hc-api.php:14-19`).\n\n**c) Encrypt the option at rest.** Use a key derived from `AUTH_KEY` / `SECURE_AUTH_KEY` (already in wp-config) to encrypt the DB value. Still readable by anyone who can read both DB + wp-config, but that's a higher bar than DB-only.\n\n**d) Per-site keys instead of a shared key.** Bigger change on the server side (would need a keys table + rotation). Correct long-term fix. Files as a follow-up if we do (a)/(b) now.\n\nRecommendation: **(a) + prefer (b)** for new installs, document (b) as the strong default in README, keep (c)/(d) as future work.","acceptance_criteria":"- [ ] Settings page no longer echoes the key value into the DOM\n- [ ] README + wp-config docs recommend the constant path as the strong default\n- [ ] Existing option-based configs continue to work (no breakage on client sites)\n- [ ] Consider filing a follow-up for (d) per-site keys","notes":"Reported in 2026-07-16 security review. Flagged as risk #1 of 3.\n\nRelated risks (separate issues):\n- Recovery installer unpinned 'latest' pull\n- No rate limiting on server API + dashboard","status":"open","priority":2,"issue_type":"bug","owner":"steve@hanlon.co.uk","created_at":"2026-07-16T10:14:21Z","created_by":"Steve Hanlon","updated_at":"2026-07-16T10:14:21Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-8gb","title":"Add auto-updates from Gitea via Plugin Update Checker","description":"Enable this plugin (and eventually the two other in-house plugins) to auto-update when a new version is pushed to Gitea's main branch, so field techs pick up fixes without manual re-installs.\n\nApproach: vendor YahnisElsts/plugin-update-checker (PUC) as a git submodule under `vendor/plugin-update-checker`, wire it up in `att-site-healthcheck.php` to poll a `updates.json` (or equivalent metadata file) served from the Gitea repo's main branch.\n\nOnce wired, WP's normal update flow surfaces new versions in Dashboard → Updates and honours site auto-update settings.","design":"**Library**: YahnisElsts/plugin-update-checker (PUC) v5.x — vendored as git submodule at `vendor/plugin-update-checker`.\n\n**Metadata source**: static `updates.json` committed to the plugin repo main branch, fetched via Gitea raw URL. Chosen over Gitea's Releases API because:\n- No auth needed if repo is readable from client sites' networks\n- Simple to bump in a release commit (version + download_url)\n- Avoids coupling to Gitea-specific API quirks\n\n**Wiring** (approx, in main plugin file after ABSPATH guard):\n```php\nrequire_once ATT_HC_PLUGIN_DIR . 'vendor/plugin-update-checker/plugin-update-checker.php';\n$updater = YahnisElsts\\PluginUpdateChecker\\v5\\PucFactory::buildUpdateChecker(\n 'https://\u003cgitea-host\u003e/steve/att-site-healthcheck/raw/branch/main/updates.json',\n ATT_HC_PLUGIN_FILE,\n 'att-site-healthcheck'\n);\n```\n\n**Release flow**:\n1. Bump `Version:` in plugin header + `ATT_HC_VERSION` constant\n2. Bump `version` + `download_url` in `updates.json` (pointing at a zip — either a Gitea release asset or a raw branch zipball)\n3. Commit + push to main\n4. Client sites pick it up on next WP update check (twice-daily) or manual 'Check again'\n\n**Later**: replicate the same submodule + updates.json pattern in the two sibling plugins.","acceptance_criteria":"- [ ] PUC vendored as git submodule under `vendor/plugin-update-checker`\n- [ ] Plugin bootstrap wires PUC against a Gitea raw URL for `updates.json`\n- [ ] `updates.json` template committed to repo main branch with current version\n- [ ] Bumping version + updates.json + pushing to main causes a test WP site to see the update in Dashboard → Updates\n- [ ] One-click update from WP admin installs the new version and the plugin remains active\n- [ ] README documents the release flow (bump header version, bump updates.json, push)\n- [ ] Pattern documented well enough to replicate for the other two in-house plugins","notes":"Implementation notes (2026-07-16):\n\nDeviated from original design: PUC is vendored directly under `vendor/plugin-update-checker/` (not a git submodule).\n\nReason: Gitea's `archive/main.zip` endpoint does NOT include submodule contents. A submodule-based approach would mean auto-downloaded update ZIPs are missing PUC entirely and fatal on activation. User confirmed vendored approach (2026-07-16).\n\n**Files added/changed:**\n- `vendor/plugin-update-checker/` — vendored PUC v5.7 (trimmed: no build/, vendor/, examples/, composer.json, phpcs.xml)\n- `att-site-healthcheck.php` — loads PUC and calls `PucFactory::buildUpdateChecker()` pointing at Gitea raw `updates.json`\n- `updates.json` — metadata file at repo root, served via Gitea raw URL\n- `README.md` — release flow + PUC-update instructions\n\n**Metadata URL**: https://git.h12e.com/steve/wp-healthcheck/raw/branch/main/updates.json\n**Download URL**: https://git.h12e.com/steve/wp-healthcheck/archive/main.zip\n\n**Folder rename**: PUC's base `UpdateChecker::fixDirectoryName()` handles the mismatch between Gitea's archive folder (`wp-healthcheck`) and the WP plugin slug (`att-site-healthcheck`) automatically via the `upgrader_source_selection` filter.\n\n**PUC v5 alias**: verified — `YahnisElsts\\PluginUpdateChecker\\v5\\PucFactory` resolves to v5p7's implementation.\n\n**Testing needed on real WP site:**\n1. Install this version, confirm no PHP errors on activation\n2. Bump version to 0.1.1 in header + updates.json, push\n3. Wait 12h OR click 'Check again' on Dashboard → Updates\n4. Confirm update offered, install it, confirm plugin still active + slug preserved\n\nOnce tested and confirmed working, replicate the same three-file pattern (vendor/, updates.json, main-plugin PUC wiring block) in the other two in-house plugins.","status":"closed","priority":2,"issue_type":"feature","assignee":"Steve Hanlon","owner":"steve@hanlon.co.uk","created_at":"2026-07-16T08:44:49Z","created_by":"Steve Hanlon","updated_at":"2026-07-16T08:52:50Z","started_at":"2026-07-16T08:47:36Z","closed_at":"2026-07-16T08:52:50Z","close_reason":"Implemented and pushed as commit 19d726f. Awaiting real-WP-site verification per the release-flow test in the notes before replicating to the two sibling plugins.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-dy9","title":"Plugin: Notes for next time → seed prereq notes on next session","description":"Add a 'Notes for next time' step at the end of the flow as a handover for whoever picks up the next engagement. On starting a new session for the same site_key, the server's step history for the handover step is pulled and used to pre-populate the 'Before You Start' (before) step's notes — prefixed with the prior session's date so the carry-over is obvious.\n\nImplementation:\n- New step file includes/steps/125-handover.php using the existing step pattern (id=handover, standard notes field). No schema or API change required since this is just another step.\n- ATT_HC_Session::start() does a best-effort step_history(handover, site_key, limit=1, exclude_id=current) and on success calls update_step('before', NOT_STARTED, prefix + notes) on the new session. Silent degrade if API unreachable — start should still succeed.\n- Same auto-seed for resume()? Probably not — resuming an existing session would clobber whatever the tech had already typed. Only seed on a genuinely new start.\n\nUser asked for this 2026-06-29 — they want a low-friction handover so engagement context survives between visits.","status":"closed","priority":2,"issue_type":"feature","assignee":"Steve Hanlon","owner":"steve@hanlon.co.uk","created_at":"2026-06-30T09:14:53Z","created_by":"Steve Hanlon","updated_at":"2026-06-30T09:17:44Z","started_at":"2026-06-30T09:15:12Z","closed_at":"2026-06-30T09:17:44Z","close_reason":"Shipped. New step file includes/steps/125-handover.php (id=handover, title='Notes for next time') with blurb + sub_items prompting the tech for what to flag. ATT_HC_Session::start() now ends with a best-effort seed_before_notes_from_prior_handover() call that pulls the prior session's handover notes via step_history(handover, site_key, 1, current_id) and writes them into this session's 'before' step notes prefixed with 'From previous session (YYYY-MM-DD):'. Silent degrade on API failure so the session is never blocked from being created. Verified end-to-end against the live server: handover-test-XXXX site exercises full flow, no-handover-XXXX site confirms no false-positive seed. Plugin-only change — no server deploy needed. Test rows purged from MySQL.","dependency_count":0,"dependent_count":0,"comment_count":0} @@ -24,6 +25,7 @@ {"_type":"issue","id":"hc-5ix.9","title":"Smoke test on testsite: full end-to-end run through the checklist","notes":"Built in phase-1 scaffold; passing lint + WP-eval end-to-end smoke test on testsite.","status":"closed","priority":2,"issue_type":"task","owner":"steve@hanlon.co.uk","created_at":"2026-06-11T14:36:15Z","created_by":"Steve Hanlon","updated_at":"2026-06-11T14:49:29Z","closed_at":"2026-06-11T14:49:29Z","labels":["phase-1"],"dependencies":[{"issue_id":"hc-5ix.9","depends_on_id":"hc-5ix","type":"parent-child","created_at":"2026-06-11T15:36:14Z","created_by":"Steve Hanlon","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-5ix.8","title":"README + install instructions + screenshots placeholder","notes":"Built in phase-1 scaffold; passing lint + WP-eval end-to-end smoke test on testsite.","status":"closed","priority":2,"issue_type":"chore","owner":"steve@hanlon.co.uk","created_at":"2026-06-11T14:36:14Z","created_by":"Steve Hanlon","updated_at":"2026-06-11T14:49:29Z","closed_at":"2026-06-11T14:49:29Z","labels":["phase-1"],"dependencies":[{"issue_id":"hc-5ix.8","depends_on_id":"hc-5ix","type":"parent-child","created_at":"2026-06-11T15:36:14Z","created_by":"Steve Hanlon","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-5ix","title":"Build WordPress Healthcheck plugin (stepper through steps.md)","description":"Plugin that walks a technician through the WordPress healthcheck steps documented in steps.md. Independent of the recovery plugin (which it depends on as step 0).","status":"open","priority":2,"issue_type":"epic","owner":"steve@hanlon.co.uk","created_at":"2026-06-11T11:26:32Z","created_by":"Steve Hanlon","updated_at":"2026-06-11T11:26:32Z","dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"hc-ufl","title":"Server: add rate limiting + lockout on API + /dashboard, rotate error_log","description":"Central healthcheck history server has no rate limiting or account lockout:\n\n- `server/src/Auth.php` — unlimited Bearer-key attempts, no delay, no lockout\n- `server/src/Dashboard.php:46-71` — unlimited login attempts on the /dashboard cookie-key form\n\nCombined with the shared-API-key exposure (see companion issue), a leaked or brute-forced key can be abused indefinitely with no signal.\n\nAlso: `server/src/bootstrap.php:25` calls `error_log()` on every uncaught exception with no rotation — the log grows unbounded on a busy or attacked server.","design":"**Rate limiting**: simplest workable option is a small in-DB counter table (key = client IP + endpoint, value = attempt count + window start). Reject when \u003e N attempts / window. No Redis dependency needed at current scale.\n\n**Lockout on /dashboard**: after e.g. 5 failed attempts from one IP within 15 min, return 429 with Retry-After. Keep it IP-scoped (not global) so a random attacker can't lock out real users.\n\n**Auth on API endpoints**: constant-time compare is already correct (`Auth.php:20` uses `hash_equals`). Add: increment failed-attempt counter, refuse to serve after threshold. Consider structured logging of each rejection with IP + user-agent for later review.\n\n**Log rotation**: either delegate to logrotate on the host (document in DEPLOY.md) OR self-rotate via a size check + rename in `bootstrap.php`'s handler.\n\nNice-to-have: session hardening on /dashboard — call `session_regenerate_id(true)` after successful auth (currently missing at `Dashboard.php:53-70`).","acceptance_criteria":"- [ ] API + /dashboard rate-limited per IP with a documented threshold\n- [ ] 429 with Retry-After returned when limit hit\n- [ ] error_log rotation strategy in place (either OS-level via DEPLOY.md docs, or in-app)\n- [ ] session_regenerate_id after /dashboard auth\n- [ ] Rejections logged with enough context to spot abuse patterns","notes":"Reported in 2026-07-16 security review. Flagged as risk #3 of 3 — lower priority than the API-key and recovery-installer issues but worth tackling in the same sweep since it's server-side and cheap.\n\nAlso noted (not required for close): session fixation on /dashboard is theoretically possible but requires attacker to first set a victim's PHPSESSID — high bar. Adding session_regenerate_id closes it cheaply.","status":"open","priority":3,"issue_type":"bug","owner":"steve@hanlon.co.uk","created_at":"2026-07-16T10:14:51Z","created_by":"Steve Hanlon","updated_at":"2026-07-16T10:14:51Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-u5c","title":"Add Google Analytics and Search Console healthcheck steps","description":"Add two new healthcheck steps between performance (Step 7) and security (Step 8): a Google Analytics check that sniffs the homepage for GA4/GTM/UA snippets and detects known analytics plugins, and a Google Search Console check that looks for verification meta tags, sitemap reachability, robots.txt Disallow rules, and the WP 'Discourage search engines' setting. Updates steps.md to match.","status":"closed","priority":3,"issue_type":"feature","assignee":"Steve Hanlon","owner":"steve@hanlon.co.uk","created_at":"2026-07-16T08:44:39Z","created_by":"Steve Hanlon","updated_at":"2026-07-16T08:44:56Z","started_at":"2026-07-16T08:44:44Z","closed_at":"2026-07-16T08:44:56Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-5ix.27","title":"Self-hosted update channel: plugin checks a private URL for new releases and offers one-click update from wp-admin","description":"Lightweight wrapper around the WP plugin update transient: site_transient_update_plugins filter that adds an entry for ourselves if a newer release exists at a configured URL. URL hosts a JSON manifest + zip. Lets technicians keep clients up to date without manually re-uploading the zip every check.","status":"open","priority":3,"issue_type":"task","owner":"steve@hanlon.co.uk","created_at":"2026-06-11T14:40:30Z","created_by":"Steve Hanlon","updated_at":"2026-06-11T14:40:30Z","labels":["phase-3"],"dependencies":[{"issue_id":"hc-5ix.27","depends_on_id":"hc-5ix","type":"parent-child","created_at":"2026-06-11T15:40:29Z","created_by":"Steve Hanlon","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"hc-5ix.25","title":"Step 12 (Wrap-up): pre-fill report with all automated findings, attach diff vs. previous session, optionally push summary to ManageWP/WP Umbrella","notes":"wrap_up step's autocheck walks all other steps' stored findings, counts bad/warn separately, lists the top 6-8 examples, and identifies any blocked steps. Gives the technician a quick 'roll-up' before they finish. The report itself already embeds every finding verbatim.","status":"closed","priority":3,"issue_type":"task","owner":"steve@hanlon.co.uk","created_at":"2026-06-11T14:36:26Z","created_by":"Steve Hanlon","updated_at":"2026-06-11T15:13:15Z","started_at":"2026-06-11T15:05:01Z","closed_at":"2026-06-11T15:13:15Z","labels":["phase-3"],"dependencies":[{"issue_id":"hc-5ix.25","depends_on_id":"hc-5ix","type":"parent-child","created_at":"2026-06-11T15:36:25Z","created_by":"Steve Hanlon","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} diff --git a/LICENSE b/LICENSE index 779cce7..e65d146 100644 --- a/LICENSE +++ b/LICENSE @@ -1,201 +1,47 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +ATT Site Healthcheck — Proprietary Software License - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +Copyright (c) 2026 Steve Hanlon. All rights reserved. - 1. Definitions. +This software and its source code are the confidential and proprietary +property of the copyright holder. No rights are granted except as +expressly set out below. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +1. Permitted use. + Sites that have been explicitly authorised in writing by the copyright + holder ("Authorised Sites") may install, run, and receive automatic + updates of this software solely for the operation of that Authorised + Site. No other use is permitted. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. +2. Restrictions. + Except as permitted above, you may not: + (a) copy, modify, merge, publish, distribute, sublicense, sell, + rent, lease, or otherwise transfer the software or any portion + of it; + (b) reverse engineer, decompile, or disassemble the software, + except to the extent that such activity is expressly permitted + by applicable law notwithstanding this limitation; + (c) remove or alter any copyright, trademark, or other proprietary + notices in the software. - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. +3. Third-party components. + This distribution includes the Plugin Update Checker library by + Janis Elsts, which is licensed under the MIT License. See + vendor/plugin-update-checker/license.txt for that license text. The + present proprietary license applies only to the balance of the + software authored by the copyright holder. - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. +4. No warranty. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE + FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. +5. Termination. + Any use in breach of this license terminates the licence + automatically. On termination you must uninstall the software and + destroy all copies in your possession. - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of tracking or otherwise improving the Work, - but excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for describing the origin of the Work and - reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Support. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or support. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2026 Steve Hanlon - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. +For licensing enquiries, contact the copyright holder. diff --git a/att-site-healthcheck.php b/att-site-healthcheck.php index 610f327..457901b 100644 --- a/att-site-healthcheck.php +++ b/att-site-healthcheck.php @@ -2,10 +2,10 @@ /** * Plugin Name: ATT Site Healthcheck * Description: Walks a technician through a structured WordPress site healthcheck. Steps are drop-in PHP files so adding/removing one is a single file change. - * Version: 0.1.2 + * Version: 0.1.3 * Author: Steve Hanlon - * License: Apache-2.0 - * License URI: https://www.apache.org/licenses/LICENSE-2.0 + * License: Proprietary + * License URI: https://git.h12e.com/steve/wp-healthcheck/raw/branch/main/LICENSE * Requires PHP: 7.4 * * Internal/agency tool — not distributed via WP.org. See beads decision hc-5ix.26. @@ -15,7 +15,7 @@ if (!defined('ABSPATH')) { exit; } -define('ATT_HC_VERSION', '0.1.2'); +define('ATT_HC_VERSION', '0.1.3'); define('ATT_HC_PLUGIN_FILE', __FILE__); define('ATT_HC_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('ATT_HC_PLUGIN_URL', plugin_dir_url(__FILE__)); diff --git a/updates.json b/updates.json index c7f2d86..d24ec49 100644 --- a/updates.json +++ b/updates.json @@ -1,12 +1,12 @@ { "name": "ATT Site Healthcheck", "slug": "att-site-healthcheck", - "version": "0.1.2", + "version": "0.1.3", "author": "Steve Hanlon", "requires": "6.0", "tested": "6.6", "requires_php": "7.4", - "last_updated": "2026-07-16 11:15:00", + "last_updated": "2026-07-16 13:00:00", "download_url": "https://git.h12e.com/steve/wp-healthcheck/archive/main.zip", "sections": { "description": "Walks a technician through a structured WordPress site healthcheck. Steps are drop-in PHP files so adding/removing one is a single file change.",