All checks were successful
Deploy Indiekit Server / deploy (push) Successful in 1m20s
- patch-ap-inbox-delivery-debug: two fixes for diagnosing missing inbound AP interactions (likes, boosts, replies not appearing in notifications) Fix A (federation-setup.js): change ["fedify","federation","inbox"] log category from lowestLevel "fatal" → "error" so HTTP Signature verification failures are now visible in server logs instead of being silently swallowed. The original "fatal" level was hiding real delivery rejections (401s) that cause remote servers to stop retrying. Fix B (federation-bridge.js): add a pre-signature-check console.info for every inbox POST when AP_DEBUG=1 or AP_LOG_LEVEL=debug. Confirms whether remote servers are reaching our inbox at all (nginx/routing check). - memory/project_activitypub.md: document full inbound activity pipeline, _publicationUrl dependency, body buffering, and how to use new diagnostics Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
117 lines
5.2 KiB
JavaScript
117 lines
5.2 KiB
JavaScript
/**
|
|
* Patch: add inbox delivery diagnostics.
|
|
*
|
|
* Problems:
|
|
* 1. The ["fedify","federation","inbox"] LogTape category is hardcoded to
|
|
* lowestLevel "fatal", hiding HTTP Signature verification failures (401s).
|
|
* Remote servers that receive 401s stop retrying → activities are lost.
|
|
* 2. No request-level logging for incoming inbox POSTs, so we can't tell
|
|
* whether remote servers are even attempting delivery.
|
|
*
|
|
* Fix A (federation-setup.js):
|
|
* Change inbox log category from "fatal" → "error".
|
|
* Real verification failures (wrong key, clock skew, digest mismatch) surface.
|
|
* High-volume 404/410 key-fetch warnings from deleted actors stay silent.
|
|
*
|
|
* Fix B (federation-bridge.js):
|
|
* Add a console.info before fromExpressRequest() that logs every POST to an
|
|
* inbox path (path + content-type + raw body length). Fires BEFORE Fedify's
|
|
* signature check, confirming whether remote servers reach our inbox at all.
|
|
* Guarded by AP_LOG_LEVEL=debug or AP_DEBUG=1 to keep production logs quiet.
|
|
*/
|
|
|
|
import { access, readFile, writeFile } from "node:fs/promises";
|
|
|
|
const MARKER_A = "// [patch] ap-inbox-delivery-debug-A";
|
|
const MARKER_B = "// [patch] ap-inbox-delivery-debug-B";
|
|
|
|
// ── Fix A: federation-setup.js — inbox logger level ──────────────────────────
|
|
|
|
const setupCandidates = [
|
|
"node_modules/@rmdes/indiekit-endpoint-activitypub/lib/federation-setup.js",
|
|
"node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/lib/federation-setup.js",
|
|
];
|
|
|
|
const OLD_INBOX_LOGGER = ` {
|
|
// Noise guard: HTTP Signature verification failures are expected for
|
|
// incoming activities from servers with expired/gone keys (e.g. deleted
|
|
// actors, migrated servers). These produce high log volume with no
|
|
// actionable signal — suppress everything below fatal.
|
|
category: ["fedify", "federation", "inbox"],
|
|
sinks: ["console"],
|
|
lowestLevel: "fatal",
|
|
},`;
|
|
|
|
const NEW_INBOX_LOGGER = ` {
|
|
// Surfacing real verification failures (wrong key, clock skew, digest
|
|
// mismatch) at "error" level while keeping high-volume key-fetch
|
|
// 404/410 warnings from deleted actors silent. ${MARKER_A}
|
|
category: ["fedify", "federation", "inbox"],
|
|
sinks: ["console"],
|
|
lowestLevel: "error",
|
|
},`;
|
|
|
|
// ── Fix B: federation-bridge.js — request-level inbox logging ────────────────
|
|
|
|
const bridgeCandidates = [
|
|
"node_modules/@rmdes/indiekit-endpoint-activitypub/lib/federation-bridge.js",
|
|
"node_modules/@indiekit/indiekit/node_modules/@rmdes/indiekit-endpoint-activitypub/lib/federation-bridge.js",
|
|
];
|
|
|
|
// Insert a debug log right before "const request = fromExpressRequest(req, publicationUrl);"
|
|
// This is patched by ap-base-url already so that comment marker is present.
|
|
const OLD_BRIDGE_REQUEST = ` const request = fromExpressRequest(req, publicationUrl); // ap-base-url patch`;
|
|
|
|
const NEW_BRIDGE_REQUEST = ` // Log incoming inbox POSTs before Fedify signature check. ${MARKER_B}
|
|
// Enabled by AP_LOG_LEVEL=debug or AP_DEBUG=1.
|
|
if (
|
|
(process.env.AP_LOG_LEVEL === "debug" || process.env.AP_DEBUG === "1") &&
|
|
req.method === "POST" &&
|
|
(req.path.includes("/inbox") || req.path.includes("/users/"))
|
|
) {
|
|
const _bct = (req.headers["content-type"] || "").split(";")[0].trim();
|
|
const _bsz = req._rawBody?.length ?? (req.body ? "pre-parsed" : "none");
|
|
console.info(\`[AP-inbox] POST \${req.path} ct=\${_bct} body=\${_bsz}B\`);
|
|
}
|
|
const request = fromExpressRequest(req, publicationUrl); // ap-base-url patch`;
|
|
|
|
async function exists(p) {
|
|
try { await access(p); return true; } catch { return false; }
|
|
}
|
|
|
|
async function applyPatch(candidates, oldSnippet, newSnippet, label, marker) {
|
|
let checked = 0;
|
|
let patched = 0;
|
|
for (const filePath of candidates) {
|
|
if (!(await exists(filePath))) continue;
|
|
checked++;
|
|
const source = await readFile(filePath, "utf8");
|
|
if (source.includes(marker)) {
|
|
console.log(`[postinstall] patch-ap-inbox-delivery-debug: ${label} already applied to ${filePath}`);
|
|
continue;
|
|
}
|
|
if (!source.includes(oldSnippet)) {
|
|
console.warn(`[postinstall] patch-ap-inbox-delivery-debug: ${label} snippet not found in ${filePath}`);
|
|
continue;
|
|
}
|
|
await writeFile(filePath, source.replace(oldSnippet, newSnippet), "utf8");
|
|
patched++;
|
|
console.log(`[postinstall] Applied patch-ap-inbox-delivery-debug (${label}) to ${filePath}`);
|
|
}
|
|
return { checked, patched };
|
|
}
|
|
|
|
const a = await applyPatch(setupCandidates, OLD_INBOX_LOGGER, NEW_INBOX_LOGGER, "inbox-logger-level", MARKER_A);
|
|
const b = await applyPatch(bridgeCandidates, OLD_BRIDGE_REQUEST, NEW_BRIDGE_REQUEST, "bridge-request-log", MARKER_B);
|
|
|
|
const total = a.checked + b.checked;
|
|
const totalPatched = a.patched + b.patched;
|
|
|
|
if (total === 0) {
|
|
console.log("[postinstall] patch-ap-inbox-delivery-debug: no target files found");
|
|
} else if (totalPatched === 0) {
|
|
console.log("[postinstall] patch-ap-inbox-delivery-debug: already up to date");
|
|
} else {
|
|
console.log(`[postinstall] patch-ap-inbox-delivery-debug: patched ${totalPatched} file(s)`);
|
|
}
|