open-local-audit 0.79.0 → 0.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,209 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdir, readdir, writeFile } from "node:fs/promises";
3
+ import { join, relative, sep } from "node:path";
4
+ import { compareReports, readComparisonReport, renderComparisonHtml, renderComparisonMarkdown, renderComparisonPdf } from "./compare.js";
5
+ import { writeReportOutputs } from "./output.js";
6
+ import { escapeCell, overallScore } from "./reporters.js";
7
+ // Run folders are named by UTC time, so sorting their names sorts them by date.
8
+ // v0.80.0 named runs to the second; later versions add milliseconds so that a retried run never reuses a folder.
9
+ const runIdPattern = /^\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}(?:-\d{3})?Z$/;
10
+ // A site is its host (without "www.") plus any port, path, and query; the scheme does not matter. Host names are
11
+ // already safe folder names, so different hosts never share a folder, and a path or query adds a short hash of
12
+ // itself so that "/a/b" and "/a-b" stay apart. The folder is the same on every run, which keeps the history together.
13
+ export function monitorSiteFolder(rawUrl) {
14
+ const url = new URL(rawUrl);
15
+ const host = url.hostname.toLowerCase().replace(/\.$/, "").replace(/^www\./, "");
16
+ const rest = `${url.pathname.replace(/\/+$/, "")}${url.search}`;
17
+ const identity = `${host}${url.port ? `:${url.port}` : ""}${rest}`;
18
+ const readable = rest.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
19
+ const folder = `${host.replace(/[^a-z0-9.-]/g, "-")}${url.port ? `-${url.port}` : ""}${rest ? `_${readable ? `${readable}-` : ""}${createHash("sha256").update(rest).digest("hex").slice(0, 8)}` : ""}`;
20
+ return { identity, folder };
21
+ }
22
+ export function monitorRunId(date) {
23
+ return date.toISOString().replace(/[:.]/g, "-");
24
+ }
25
+ async function previousRunIds(siteDir, runId) {
26
+ try {
27
+ const entries = await readdir(siteDir, { withFileTypes: true });
28
+ return entries
29
+ .filter((entry) => entry.isDirectory() && runIdPattern.test(entry.name) && entry.name < runId)
30
+ .map((entry) => entry.name)
31
+ .sort()
32
+ .reverse();
33
+ }
34
+ catch {
35
+ return [];
36
+ }
37
+ }
38
+ function message(error) {
39
+ return error instanceof Error ? error.message : "Unknown error";
40
+ }
41
+ function currentAlerts(report) {
42
+ const alerts = [
43
+ ["certificate", "tls-certificate-valid", "HTTPS certificate"],
44
+ ["domain", "domain-expiry", "Domain"]
45
+ ];
46
+ return alerts.flatMap(([kind, id, label]) => {
47
+ const finding = report.findings.find((item) => item.id === id);
48
+ return finding ? [{ kind, message: `${label}: ${finding.evidence[0]?.value || finding.title}` }] : [];
49
+ });
50
+ }
51
+ // Uses the newest earlier run that still has a readable report, so an interrupted run does not reset the history.
52
+ async function previousReport(siteDir, runId) {
53
+ for (const previousRunId of await previousRunIds(siteDir, runId)) {
54
+ try {
55
+ return { runId: previousRunId, report: await readComparisonReport(join(siteDir, previousRunId)) };
56
+ }
57
+ catch {
58
+ continue;
59
+ }
60
+ }
61
+ return undefined;
62
+ }
63
+ async function monitorSite(entry, slug, runId, options) {
64
+ const base = { url: entry.url, ...(entry.label ? { label: entry.label } : {}), slug, newFindings: 0, fixedFindings: 0 };
65
+ const profile = entry.profile ?? options.profile ?? "generic";
66
+ const siteDir = join(options.outDir, slug);
67
+ const reportDir = join(siteDir, runId);
68
+ let report;
69
+ try {
70
+ report = await options.audit(entry.url, profile);
71
+ }
72
+ catch (error) {
73
+ return { ...base, status: "failed", alerts: [{ kind: "failed", message: `Audit failed: ${message(error)}` }] };
74
+ }
75
+ await writeReportOutputs(report, { format: "all", outDir: reportDir, brand: options.brand });
76
+ const [reportPdf] = await writeReportOutputs(report, { format: "pdf", outDir: reportDir, brand: options.brand });
77
+ const reportPdfPath = reportPdf.path;
78
+ const score = overallScore(report);
79
+ const alerts = currentAlerts(report);
80
+ const previous = await previousReport(siteDir, runId);
81
+ if (!previous) {
82
+ return { ...base, status: "baseline", reportDir, pdfPath: reportPdfPath, score, alerts, note: "First run: baseline recorded" };
83
+ }
84
+ const previousRunId = previous.runId;
85
+ let comparison;
86
+ try {
87
+ comparison = compareReports(previous.report, report);
88
+ }
89
+ catch (error) {
90
+ return { ...base, status: "baseline", reportDir, pdfPath: reportPdfPath, score, alerts, note: `Not compared with ${previousRunId}: ${message(error)}; new baseline recorded` };
91
+ }
92
+ const comparisonPath = join(reportDir, "comparison.html");
93
+ await writeFile(join(reportDir, "comparison.md"), renderComparisonMarkdown(comparison, { brand: options.brand }));
94
+ await writeFile(comparisonPath, renderComparisonHtml(comparison, { brand: options.brand }));
95
+ const pdfPath = join(reportDir, "comparison.pdf");
96
+ await writeFile(pdfPath, await renderComparisonPdf(comparison, { brand: options.brand }));
97
+ // Certificate and domain problems already have their own alert on every run.
98
+ const newHigh = comparison.introduced
99
+ .filter((finding) => finding.severity === "high" && !["tls-certificate-valid", "domain-expiry"].includes(finding.id))
100
+ .map((finding) => ({ kind: "new-high", message: `New high issue: ${finding.title}` }));
101
+ return {
102
+ ...base,
103
+ status: "compared",
104
+ reportDir,
105
+ comparisonPath,
106
+ pdfPath,
107
+ previousRunId,
108
+ score,
109
+ previousScore: comparison.overall.before,
110
+ scoreChange: comparison.overall.change,
111
+ newFindings: comparison.introduced.length,
112
+ fixedFindings: comparison.fixed.length,
113
+ alerts: [...newHigh, ...alerts]
114
+ };
115
+ }
116
+ // Re-audits every site, compares each one with its latest earlier run in the same output folder, and writes a summary.
117
+ // Nothing is sent: the summary and reports stay on disk for the operator.
118
+ export async function runMonitor(entries, options) {
119
+ const sitesByIdentity = new Map();
120
+ const slugs = entries.map((entry) => {
121
+ const site = monitorSiteFolder(entry.url);
122
+ const earlier = sitesByIdentity.get(site.identity);
123
+ if (earlier) {
124
+ throw new Error(`Monitor input lists the same site twice: ${earlier} and ${entry.url}`);
125
+ }
126
+ sitesByIdentity.set(site.identity, entry.url);
127
+ return site.folder;
128
+ });
129
+ const runId = monitorRunId(options.now ?? new Date());
130
+ const sites = [];
131
+ for (const [index, entry] of entries.entries()) {
132
+ try {
133
+ sites.push(await monitorSite(entry, slugs[index], runId, options));
134
+ }
135
+ catch (error) {
136
+ // A report that cannot be written for one site, such as a locked file, should not stop the other sites.
137
+ sites.push({
138
+ url: entry.url,
139
+ ...(entry.label ? { label: entry.label } : {}),
140
+ slug: slugs[index],
141
+ status: "failed",
142
+ newFindings: 0,
143
+ fixedFindings: 0,
144
+ alerts: [{ kind: "failed", message: `Could not save the run: ${message(error)}` }]
145
+ });
146
+ }
147
+ }
148
+ await mkdir(options.outDir, { recursive: true });
149
+ const summaryPaths = {
150
+ markdown: join(options.outDir, `monitor-summary-${runId}.md`),
151
+ json: join(options.outDir, `monitor-summary-${runId}.json`)
152
+ };
153
+ const summary = { runId, outDir: options.outDir, sites, summaryPaths };
154
+ await writeFile(summaryPaths.markdown, renderMonitorMarkdown(summary));
155
+ await writeFile(summaryPaths.json, renderMonitorJson(summary));
156
+ return summary;
157
+ }
158
+ function relativePath(summary, path) {
159
+ return path ? relative(summary.outDir, path).split(sep).join("/") : "";
160
+ }
161
+ function siteName(site) {
162
+ return site.label ? `${site.label} (${site.url})` : site.url;
163
+ }
164
+ export function renderMonitorJson(summary) {
165
+ const sites = summary.sites.map((site) => ({
166
+ ...site,
167
+ reportDir: site.reportDir ? relativePath(summary, site.reportDir) : undefined,
168
+ comparisonPath: site.comparisonPath ? relativePath(summary, site.comparisonPath) : undefined,
169
+ pdfPath: site.pdfPath ? relativePath(summary, site.pdfPath) : undefined
170
+ }));
171
+ return `${JSON.stringify({ runId: summary.runId, sites }, null, 2)}\n`;
172
+ }
173
+ export function renderMonitorMarkdown(summary) {
174
+ const count = (status) => summary.sites.filter((site) => site.status === status).length;
175
+ const attention = summary.sites.filter((site) => site.alerts.length > 0);
176
+ const plural = (value, word) => `${value} ${word}${value === 1 ? "" : "s"}`;
177
+ const signed = (value) => (value > 0 ? `+${value}` : `${value}`);
178
+ const rows = summary.sites.map((site) => [
179
+ siteName(site),
180
+ site.status === "compared" ? `Compared with ${site.previousRunId}` : site.status === "baseline" ? (site.note ?? "Baseline") : "Failed",
181
+ site.score === undefined ? "" : `${site.score}/100`,
182
+ site.scoreChange === undefined ? "" : signed(site.scoreChange),
183
+ site.status === "compared" ? `${site.newFindings}` : "",
184
+ site.status === "compared" ? `${site.fixedFindings}` : "",
185
+ relativePath(summary, site.comparisonPath ?? (site.reportDir ? join(site.reportDir, "open-local-audit-report.html") : undefined)),
186
+ relativePath(summary, site.pdfPath)
187
+ ]);
188
+ return [
189
+ "# Website Monitoring Summary",
190
+ "",
191
+ `Run ${summary.runId}: ${plural(summary.sites.length, "site")}, ${count("compared")} compared, ${count("baseline")} baseline, ${count("failed")} failed. ${attention.length === 0 ? "No site needs attention." : `${plural(attention.length, "site")} need${attention.length === 1 ? "s" : ""} attention.`}`,
192
+ "",
193
+ "## Needs Attention",
194
+ "",
195
+ ...(attention.length === 0
196
+ ? ["Nothing new to act on."]
197
+ : attention.map((site) => `- **${siteName(site)}**: ${site.alerts.map((alert) => alert.message).join("; ")}`)),
198
+ "",
199
+ "## Sites",
200
+ "",
201
+ "| Site | Status | Score | Change | New | Fixed | Report | Client PDF |",
202
+ "| --- | --- | --- | --- | --- | --- | --- | --- |",
203
+ ...rows.map((row) => `| ${row.map(escapeCell).join(" | ")} |`),
204
+ "",
205
+ "Reports and comparisons stay on this computer; nothing has been sent.",
206
+ ""
207
+ ].join("\n");
208
+ }
209
+ //# sourceMappingURL=monitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monitor.js","sourceRoot":"","sources":["../src/monitor.ts"],"names":[],"mappings":"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"}
@@ -6,7 +6,9 @@ const pitchReasons = [
6
6
  [/^website-placeholder$/, "People who find the business online land on a placeholder instead of a website."],
7
7
  [/^http-status-ok$/, "The page returns an error, so visitors and Google may not see it at all."],
8
8
  [/^tls-certificate-valid$/, "Browsers show, or will soon show, a security warning instead of the site."],
9
+ [/^domain-expiry$/, "The domain registration is about to run out or has lapsed; if it is not renewed, the website and email stop working."],
9
10
  [/^page-indexable$/, "The page tells Google not to list it, so it cannot appear in search results."],
11
+ [/^robots-txt-allows-page$/, "The site's robots.txt tells Google not to crawl the page, so it can drop out of search results."],
10
12
  [/^https-enabled$/, "Browsers mark the site as \"Not secure\"."],
11
13
  [/^viewport-present$/, "The page does not adapt to phones, where most local searches happen."],
12
14
  [/^phone-link-present$/, "The phone number is not tap-to-call on mobile."],
@@ -1 +1 @@
1
- {"version":3,"file":"pitch-brief.js","sourceRoot":"","sources":["../src/pitch-brief.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pitch-brief.js","sourceRoot":"","sources":["../src/pitch-brief.ts"],"names":[],"mappings":"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"}
package/dist/rules.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { load } from "cheerio";
2
2
  import { findPhoneNumbersInText, getCountries, parsePhoneNumberFromString } from "libphonenumber-js/max";
3
+ import { createRequire } from "node:module";
3
4
  import { detectPageForms, hasContactOrBookingLink } from "./contact.js";
4
5
  import { cookieNames } from "./dotnet-stack.js";
5
6
  import { applyTypeContext, contextBase, expandNodeId, isLocalBusinessType, noTypeContext } from "./local-business-types.js";
@@ -916,6 +917,22 @@ function robotsHeaderBlocksIndexing(value) {
916
917
  return SEARCH_CRAWLERS.has(crawler) && blocksIndexing(directive);
917
918
  });
918
919
  }
920
+ const robotsParser = createRequire(import.meta.url)("robots-parser");
921
+ // Googlebot follows the group that names it, or the "*" group when there is none, as robots-parser does.
922
+ function robotsTxtBlock(snapshot) {
923
+ const robots = snapshot.resources?.robotsTxt;
924
+ if (!robots?.content || !hasSuccessfulResource(robots.statusCode)) {
925
+ return undefined;
926
+ }
927
+ const policy = robotsParser(new URL("/robots.txt", snapshot.finalUrl).toString(), robots.content);
928
+ if (policy.isAllowed(snapshot.finalUrl, "Googlebot") !== false) {
929
+ return undefined;
930
+ }
931
+ const lineNumber = policy.getMatchingLineNumber(snapshot.finalUrl, "Googlebot");
932
+ // Split lines the way robots-parser numbers them, including bare CR line endings.
933
+ const line = robots.content.split(/\r\n|\r|\n/)[lineNumber - 1]?.trim();
934
+ return `robots.txt blocks Googlebot from ${snapshot.finalUrl}${line ? ` (line ${lineNumber}: ${line})` : ""}`;
935
+ }
919
936
  function noindexSignals($, snapshot) {
920
937
  const signals = $("meta[name][content]")
921
938
  .toArray()
@@ -965,6 +982,20 @@ function mixedContentUrls($, snapshot) {
965
982
  }
966
983
  // Let's Encrypt and most automated issuers renew at 30 days left, so fewer than 14 means automatic renewal is failing.
967
984
  const certificateWarningDays = 14;
985
+ // A month's notice leaves time to fix a failed renewal; healthy domains that renew in their final weeks can show here too.
986
+ const domainWarningDays = 30;
987
+ const lapsingDomainStatus = /^(?:redemption ?period|pending ?delete)$/i;
988
+ function domainRiskStatus(domain) {
989
+ return domain.status.find((status) => lapsingDomainStatus.test(status.trim())) ??
990
+ (domain.daysRemaining < domainWarningDays ? "expiring" : undefined);
991
+ }
992
+ function domainEvidence(domain) {
993
+ const date = domain.expiresAt.slice(0, 10);
994
+ const days = domain.daysRemaining;
995
+ const expiry = days < 0 ? `${domain.name} expired ${date}` : `${domain.name} expires ${date} (${days} day${days === 1 ? "" : "s"})`;
996
+ const risk = domainRiskStatus(domain);
997
+ return [expiry, ...(risk && risk !== "expiring" ? [`status: ${risk}`] : []), ...(domain.registrar ? [`registrar ${domain.registrar}`] : [])].join("; ");
998
+ }
968
999
  function tlsCertificateEvidence(tls) {
969
1000
  const date = tls.validTo.slice(0, 10);
970
1001
  const status = tls.daysRemaining < 0
@@ -1093,12 +1124,15 @@ const trackingCookie = /^(?:_ga(?:_\w+)?|_gid|_gat(?:_\w+)?|_gcl_\w+|_fbp|_fbc|_
1093
1124
  // Consent platforms, IAB TCF, Google consent mode defaults, website-builder banners, and common cookie banner markup.
1094
1125
  // Matching is deliberately broad: a page that shows any sign of a consent step is not flagged.
1095
1126
  const consentTool = /cookiebot|cookielaw\.org|onetrust|optanon|cookieyes|cookie-law-info|termly\.io|iubenda|complianz|cmplz|osano|usercentrics|cmp\.quantcast\.com|__tcfapi|didomi|cookiefirst|cookie-script\.com|civiccomputing|cookiecontrol|borlabs|klaro|real-cookie-banner|moove[_-]gdpr|cookie[_-]?(?:notice|consent|banner|bar|law)|consent[_-]?(?:banner|manager)|cookiehub|axeptio|tarteaucitron|trustarc|consentmanager|gdpr[_-]?cookie|cc-window|cc-banner|sqs-cookie-banner|\bfs-cc\b|fundingchoicesmessages\.google\.com|hs-banner|hs-eu-cookie|consentPolicy|customerPrivacy|\bgtag\(\s*['"]consent['"]\s*,\s*['"]default['"]/i;
1096
- // Consent tools hold tags back as type="text/plain" until visitors accept, so only executable scripts count.
1097
- const executableScriptTypes = new Set(["", "text/javascript", "application/javascript", "module"]);
1127
+ // Consent tools hold tags back as type="text/plain" until visitors accept, and data or template blocks never run.
1128
+ // Any other type counts, including the types that optimisers such as Rocket Loader ("<hash>-text/javascript"),
1129
+ // LiteSpeed ("litespeed/javascript"), WP Rocket ("rocketlazyloadscript"), and Partytown use for scripts they run later.
1130
+ const inertScriptType = /^text\/plain$|json|importmap|speculationrules|template|^text\/html$|handlebars|mustache/;
1098
1131
  function loadedTrackers($) {
1099
1132
  const scripts = $("script")
1100
1133
  .toArray()
1101
- .filter((element) => executableScriptTypes.has(($(element).attr("type") ?? "").trim().toLowerCase()))
1134
+ // Only the MIME type counts, so "text/plain; charset=utf-8" is inert too.
1135
+ .filter((element) => !inertScriptType.test(($(element).attr("type") ?? "").split(";")[0].trim().toLowerCase()))
1102
1136
  .map((element) => `${$(element).attr("src") ?? ""} ${$(element).text()}`)
1103
1137
  .join("\n");
1104
1138
  return trackers.filter(([, pattern]) => pattern.test(scripts)).map(([name]) => name);
@@ -1206,6 +1240,16 @@ const rules = [
1206
1240
  check: ({ snapshot }) => !snapshot.tls || (snapshot.tls.authorized && snapshot.tls.daysRemaining >= certificateWarningDays),
1207
1241
  evidence: ({ snapshot }) => (snapshot.tls ? tlsCertificateEvidence(snapshot.tls) : "")
1208
1242
  },
1243
+ {
1244
+ id: "domain-expiry",
1245
+ title: "Domain registration is expiring or has lapsed",
1246
+ category: "technical-health",
1247
+ severity: "medium",
1248
+ source: "Domain registration",
1249
+ recommendation: "Check with your domain registrar that the domain renews automatically and the payment details on file are current; if the domain lapses, the website and email stop working.",
1250
+ check: ({ snapshot }) => !snapshot.domain || domainRiskStatus(snapshot.domain) === undefined,
1251
+ evidence: ({ snapshot }) => (snapshot.domain ? domainEvidence(snapshot.domain) : "")
1252
+ },
1209
1253
  {
1210
1254
  id: "page-indexable",
1211
1255
  title: "Page tells search engines not to index it",
@@ -1216,6 +1260,16 @@ const rules = [
1216
1260
  check: ({ $, snapshot }) => noindexSignals($, snapshot).length === 0,
1217
1261
  evidence: ({ $, snapshot }) => noindexSignals($, snapshot).join("; ")
1218
1262
  },
1263
+ {
1264
+ id: "robots-txt-allows-page",
1265
+ title: "robots.txt blocks search engines from this page",
1266
+ category: "search-basics",
1267
+ severity: "high",
1268
+ source: "robots.txt",
1269
+ recommendation: "Remove or narrow the robots.txt Disallow rule that matches this page so Google can crawl it and keep it in search results.",
1270
+ check: ({ snapshot }) => robotsTxtBlock(snapshot) === undefined,
1271
+ evidence: ({ snapshot }) => robotsTxtBlock(snapshot) ?? ""
1272
+ },
1219
1273
  {
1220
1274
  id: "mixed-content-absent",
1221
1275
  title: "Secure page loads files over plain HTTP",