Skip to content

feat(tcfeed): add RSS feeds as a third source, kept as OPML - #118

Merged
ralyodio merged 1 commit into
masterfrom
worktree-tcfeed-rss
Aug 13, 2026
Merged

feat(tcfeed): add RSS feeds as a third source, kept as OPML#118
ralyodio merged 1 commit into
masterfrom
worktree-tcfeed-rss

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor
tcfeed rss add https://leaddev.com/feed
tcfeed rss list
tcfeed rss remove https://leaddev.com/feed
tcfeed: 58 to consider — 39 from r/coolgithubprojects, 3 from search (stars:1000..10000), 16 from 2 feeds

Feeds are not parsed

The bodies are concatenated and handed to reposIn(). That function already looks for repository links anywhere in a document, which is the only thing wanted from a feed, and it behaves identically on RSS, Atom, and the HTML some of them serve by mistake — none of which a feed parser would agree about. github.blog alone contributed 16 repositories on the first run. (leaddev.com contributed none — it is a valid feed that simply does not link repositories, and its zero shows on the summary line rather than being hidden.)

OPML, at ~/.moshcode/feeds.opml

One reason each:

  • OPML because a feed list is the one thing here somebody already has somewhere else. Every reader imports and exports it, so the list can arrive from one and leave for another without this becoming the only place it lives.
  • Under ~/.moshcode because that is the directory moshcode's /save copies to the account.

I checked the sync server rather than assuming: it validates shape, not filenames — no .., no leading slash, ≤32 files, ≤256KB — so it accepts feeds.opml with nothing deployed. Only moshcode's own client-side SYNCED_FILES has to name it, which is a separate one-line change in that repo.

Nothing here depends on moshcode being installed. The file is created on demand and TCFEED_OPML moves it anywhere.

Failure and safety

  • A feed that fails is named and skipped: tcfeed: rss https://… (HTTP network). One dead blog must not be why a scan produced nothing, and "3 feeds failed" is a number to shrug at where the URL is something to go and fix.
  • Only http(s) is accepted. The list is fetched with curl, and a file:// entry in an OPML that came from somewhere else would make a shared feed list read this machine's disk.
  • Nothing validates a URL by fetching it at add time. A feed that is down this minute is still a feed.

Verified

tsc --strict clean, every path against live feeds:

Case Result
rss / rss list empty points at the path and shows the add syntax
rss add ×2, one duplicate added, already there, valid OPML on disk
rss remove removed; removing an absent URL errors and suggests rss list
rss add file:///etc/passwd refused
scan with 2 feeds 16 from 2 feeds, deduped across all three sources
scan with a dead feed feed named, 0 from 1 feed, run continues

🤖 Generated with Claude Code

  tcfeed rss add https://leaddev.com/feed
  tcfeed rss list
  tcfeed rss remove https://leaddev.com/feed

Feed bodies are concatenated and handed to reposIn(), not parsed. That
function already looks for repository links anywhere in a document,
which is the only thing wanted from a feed, and it behaves the same on
RSS, Atom and the HTML some of them serve by mistake - none of which a
feed parser would agree about. github.blog alone contributed 16
repositories on the first run.

OPML, at ~/.moshcode/feeds.opml, for one reason each. OPML because a
feed list is the one thing here somebody already has somewhere else:
every reader imports and exports it, so the list can arrive from one
and leave for another without this becoming the only place it exists.
Under ~/.moshcode because that is the directory moshcode's `/save`
copies to the account. That server validates shape rather than
filenames - no `..`, no leading slash, 32 files, 256KB - so it takes
this without anything being deployed; only moshcode's own SYNCED_FILES
has to name it, which is a separate change. Nothing here depends on
moshcode being installed: the file is made on demand and TCFEED_OPML
moves it anywhere.

A feed that fails is named and skipped rather than counted. One dead
blog must not be why a scan produced nothing, and "3 feeds failed" is a
number to shrug at where the URL is something to go and fix.

The summary line now names every source including the ones that
contributed nothing, because a feed that has stopped mentioning
repositories looks exactly like a feed nobody added until its zero is
on the screen.

Only http(s) is accepted. The list is fetched with curl, and a
`file://` entry in an OPML that came from somewhere else would make a
shared feed list read this machine's disk.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

ThreatCrush Security Scan

67 finding(s)

HIGH/CRITICAL: 11 | MEDIUM: 55 | LOW: 1

Severity Rule Location
HIGH secret-aws-access-key prd/0003-detect-hardcoded-secrets-before-they-are-committed-or-served.md:126
HIGH sh-eval-expansion .githooks/pre-commit:26
HIGH sh-remote-script-execution apps/web/public/install.sh:272
HIGH sh-remote-script-execution apps/web/public/install.sh:320
HIGH secret-generic-credential modules/spend-guard/config/example.conf.toml:13
HIGH secret-generic-credential modules/spend-guard/README.md:84
HIGH secret-generic-credential PRD.md:268
HIGH tls-verification-disabled prd/0004-find-dangerous-code-patterns-without-pretending-to-be-a-compiler.md:121
HIGH tls-verification-disabled prd/0004-find-dangerous-code-patterns-without-pretending-to-be-a-compiler.md:122
HIGH sh-remote-script-execution scripts/smoke-test.sh:46
HIGH sh-remote-script-execution scripts/smoke-test.sh:47
MEDIUM insecure-temp-file .githooks/commit-msg:16
MEDIUM insecure-temp-file .githooks/post-commit:20
MEDIUM js-shell-exec-interpolation apps/cli/src/commands/init.ts:70
MEDIUM js-shell-exec-interpolation apps/cli/src/commands/init.ts:79
MEDIUM js-shell-exec-interpolation apps/cli/src/commands/service.ts:88
MEDIUM js-shell-exec-interpolation apps/cli/src/commands/service.ts:111
MEDIUM sql-template-interpolation apps/cli/src/core/state.ts:121
MEDIUM sql-template-interpolation apps/cli/src/core/state.ts:125
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:31
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:33
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:34
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:35
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:36
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:43
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:49
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:56
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:63
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:82
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:84
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:85
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:93
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:98
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:105
MEDIUM js-shell-exec-interpolation apps/cli/src/daemon/firewall/adapters.ts:112
MEDIUM js-shell-exec-interpolation apps/cli/src/index.ts:419
MEDIUM js-unescaped-html-sink apps/web/src/app/about/page.tsx:180
MEDIUM js-unescaped-html-sink apps/web/src/app/about/page.tsx:184
MEDIUM js-open-redirect apps/web/src/app/auth/login/page.tsx:50
MEDIUM js-unescaped-html-sink apps/web/src/app/blog/[slug]/page.tsx:125
MEDIUM js-unescaped-html-sink apps/web/src/app/blog/[slug]/page.tsx:153
MEDIUM js-unescaped-html-sink apps/web/src/app/blog/[slug]/page.tsx:157
MEDIUM js-unescaped-html-sink apps/web/src/app/get-whitepaper/page.tsx:346
MEDIUM js-unescaped-html-sink apps/web/src/app/layout.tsx:211
MEDIUM js-unescaped-html-sink apps/web/src/app/layout.tsx:215
MEDIUM js-unescaped-html-sink apps/web/src/app/layout.tsx:219
MEDIUM js-unescaped-html-sink apps/web/src/app/page.tsx:120
MEDIUM js-unescaped-html-sink apps/web/src/app/store/[slug]/page.tsx:107
MEDIUM js-open-redirect apps/web/src/components/funding/FundingClient.tsx:97
MEDIUM manifest-install-lifecycle-script package.json:24

…and 17 more. Full results in the Security tab.

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit 2dc47f7 into master Aug 13, 2026
11 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.

1 participant