Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
2f90047
Accept MPP method tempo (push mode) when MPP_TEMPO_RECIPIENT is set
claude Oct 4, 2026
6ada795
Clearer /api/explain description for agents
claude Oct 5, 2026
e2c21e4
Merge remote branch (already merged history)
claude Oct 5, 2026
57e398c
Add glama.json to claim the Glama listing
claude Oct 5, 2026
88577ee
Merge remote branch (already merged history)
claude Oct 5, 2026
2eeeeec
MCP registry: clearer description (says when an agent would use it)
claude Oct 5, 2026
ce242d7
Merge remote branch (already merged history)
claude Oct 5, 2026
71f6a3e
Homepage: a row of prices right under the intro
claude Oct 6, 2026
fd7ae48
Merge remote branch (already merged history)
claude Oct 6, 2026
193799b
Usage log: record the network a refused payment was tried on
claude Oct 6, 2026
2d888e4
Merge branch 'claude/x402-agents-solana-payments-nceg9b' of https://g…
claude Oct 6, 2026
322505c
Pay in RLUSD on the XRP Ledger (x402 exact, xrpl:0)
claude Oct 7, 2026
aa35a9d
Merge branch 'claude/x402-agents-solana-payments-nceg9b' of https://g…
claude Oct 7, 2026
633f050
XRPL: also accept payers built on t54's SDK
claude Oct 7, 2026
3033055
Merge remote-tracking branch 'origin/main' into claude/x402-agents-so…
claude Oct 7, 2026
fdab3b3
SEO: canonical tag, robots.txt and sitemap.xml for the homepage
claude Oct 7, 2026
0027283
Merge branch 'claude/x402-agents-solana-payments-nceg9b' of https://g…
claude Oct 7, 2026
823b132
CI: run the tests on every pull request and on main
claude Oct 7, 2026
60e2caa
Merge branch 'claude/x402-agents-solana-payments-nceg9b' of https://g…
claude Oct 7, 2026
d81e01e
Usage log: record why an MPP credential was refused
claude Oct 7, 2026
7a491d3
Merge branch 'claude/x402-agents-solana-payments-nceg9b' of https://g…
claude Oct 7, 2026
84c2f4e
Pay in USDC on Algorand (ALGORAND_PAY_TO)
claude Oct 8, 2026
a6cec2a
Merge remote branch
claude Oct 8, 2026
aa499c8
Name the seller in the 402: x402-merchant extension
claude Oct 9, 2026
7ec7ce1
Merge remote branch (already in main)
claude Oct 9, 2026
9c7b5d0
MCP: output schemas and structured content on every tool
claude Oct 9, 2026
3fdf50f
Merge remote branch (already in main)
claude Oct 9, 2026
80dd8e2
Merge stale remote branch claude/x402-agents-solana-payments-nceg9b
claude Oct 13, 2026
725218e
Discovery: a name and description per resource in /.well-known/x402
claude Oct 13, 2026
97ffd96
Merge stale remote branch claude/x402-agents-solana-payments-nceg9b
claude Oct 13, 2026
775fa73
Security headers on every answer
claude Oct 13, 2026
f2ea313
Merge stale remote branch claude/x402-agents-solana-payments-nceg9b
claude Oct 13, 2026
3ff3a26
Weekly dependency audit with one issue while a finding is open
claude Oct 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/scripts/audit-check.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Weekly dependency audit (Dependabot alerts are off). Reads `npm audit --json` and the lockfile and
// prints, as Markdown for an issue, the high and critical findings a production install can reach.
// Findings reachable only through a package named in IGNORE (comma-separated) are left out: @x402/paywall
// bundles browser wallet libraries (WalletConnect, Reown) that the server never runs.
// Usage: node audit-check.mjs audit.json package-lock.json > report.md (empty output = nothing to report)
import { readFileSync } from "node:fs";

const [auditPath, lockPath] = process.argv.slice(2);
const audit = JSON.parse(readFileSync(auditPath, "utf8"));
if (audit.error) throw new Error(`npm audit failed: ${audit.error.summary || JSON.stringify(audit.error)}`);
const pkgs = JSON.parse(readFileSync(lockPath, "utf8")).packages || {};
const ignore = new Set((process.env.IGNORE || "").split(",").map((s) => s.trim()).filter(Boolean));

// Where Node finds `name` when `from` requires it: the nearest node_modules on the way up to the root.
const resolve = (from, name) => {
for (let dir = from; ; ) {
const path = (dir ? `${dir}/` : "") + `node_modules/${name}`;
if (pkgs[path]) return path;
if (!dir) return null;
const i = dir.lastIndexOf("/node_modules/");
dir = i === -1 ? "" : dir.slice(0, i);
}
};

// Every installed path a production install reaches from the root, skipping ignored packages.
const reached = new Set();
const root = pkgs[""] || {};
const queue = Object.keys({ ...root.dependencies, ...root.optionalDependencies }).map((n) => [n, ""]);
while (queue.length) {
const [name, from] = queue.pop();
if (ignore.has(name)) continue;
const path = resolve(from, name);
if (!path || reached.has(path)) continue;
reached.add(path);
const e = pkgs[path];
for (const dep of Object.keys({ ...e.dependencies, ...e.optionalDependencies, ...e.peerDependencies })) queue.push([dep, path]);
}

const rank = { critical: 0, high: 1 };
const found = Object.values(audit.vulnerabilities || {})
.filter((v) => v.severity in rank && (v.nodes || []).some((n) => reached.has(n)))
.sort((a, b) => rank[a.severity] - rank[b.severity] || a.name.localeCompare(b.name));
if (found.length) {
const fix = (f) => (f === true ? "update available" : f && f.name ? `fix needs ${f.name}@${f.version}${f.isSemVerMajor ? " (major)" : ""}` : "no fix yet");
const lines = found.map((v) => {
const advisories = [...new Map(v.via.filter((x) => typeof x === "object").map((x) => [x.url, `[${x.title}](${x.url})`])).values()];
const through = v.via.filter((x) => typeof x === "string");
return `- **${v.name}** ${v.severity}, ${v.range}: ${advisories.join("; ") || `through ${through.join(", ")}`}. ${fix(v.fixAvailable)}.`;
});
console.log(`The weekly \`npm audit\` found ${found.length} high or critical finding(s) in production dependencies${ignore.size ? ` (not counting what only ${[...ignore].join(", ")} pulls in)` : ""}:\n\n${lines.join("\n")}\n\nFix with \`npm install <package>@<fixed version>\` or \`npm audit fix --omit=dev\`, run the tests, and open a PR. This issue closes itself after a clean weekly run.`);
}
43 changes: 43 additions & 0 deletions .github/workflows/audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Dependency audit
# Every Monday: npm audit on PlainText's production dependencies (Dependabot alerts are off on this repo).
# A high or critical finding the server can reach opens one issue labelled dependency-audit (GitHub
# emails the owner), or adds the new list to the open one; the next clean run closes it.
on:
schedule:
- cron: "17 5 * * 1"
workflow_dispatch: {}
push:
branches: ['claude/**']
paths: ['.github/scripts/audit-check.mjs', '.github/workflows/audit.yml']
permissions:
contents: read
issues: write
jobs:
audit:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: 22
# npm audit exits non-zero whenever it finds anything; the next step decides what counts.
- run: npm audit --omit=dev --package-lock-only --json > "$RUNNER_TEMP/audit.json" || true
- name: High and critical findings the server can reach
run: node "$GITHUB_WORKSPACE/.github/scripts/audit-check.mjs" "$RUNNER_TEMP/audit.json" package-lock.json > "$RUNNER_TEMP/report.md"
- name: Keep one issue open while findings remain
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
report="$RUNNER_TEMP/report.md"
num=$(gh issue list --label dependency-audit --state open --json number --jq '.[0].number // empty')
if [ -s "$report" ]; then
cat "$report" >> "$GITHUB_STEP_SUMMARY"
if [ -n "$num" ]; then gh issue comment "$num" --body-file "$report"; exit 0; fi
gh label create dependency-audit --color B60205 --description "Weekly npm audit found a high or critical advisory" 2>/dev/null || true
gh issue create --title "Dependency audit: high or critical advisory" --label dependency-audit --body-file "$report"
else
echo "No high or critical findings the server can reach." >> "$GITHUB_STEP_SUMMARY"
if [ -n "$num" ]; then gh issue close "$num" --comment "The weekly audit is clean again."; fi
fi
Loading