Skip to content

feat: harden RSS article opening and upgrade CI runtime#18

Merged
SpeechlessPanda merged 1 commit into
mainfrom
feat/v0.1.6-release-hardening
Mar 31, 2026
Merged

feat: harden RSS article opening and upgrade CI runtime#18
SpeechlessPanda merged 1 commit into
mainfrom
feat/v0.1.6-release-hardening

Conversation

@SpeechlessPanda

Copy link
Copy Markdown
Owner

Summary

  • route RSS article opening through main-process IPC with external URL policy checks, and expose openRssArticle through preload/composables to remove direct renderer window.open usage
  • improve RSS reader UX by adding unread-only inline 已读 actions and keeping title click open behavior consistent with read-state updates
  • upgrade CI/release workflows to Node 24-era actions/runtime and rewrite OAuth setup guide with explicit Device Flow requirements

Test Plan

  • pnpm exec node --test src/renderer/src/composables/useRssActions.test.mjs src/renderer/src/views/RssReaderView.facade.test.mjs src/renderer/src/views/RssReaderView.redesign.test.mjs src/main/preload.test.js src/main/ipc/rssIpc.test.js src/main/policies/externalUrlPolicy.test.js
  • pnpm run verify:premerge

Copilot AI review requested due to automatic review settings March 31, 2026 14:03
@SpeechlessPanda SpeechlessPanda merged commit dfd1383 into main Mar 31, 2026
4 checks passed
@SpeechlessPanda SpeechlessPanda deleted the feat/v0.1.6-release-hardening branch March 31, 2026 14:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens RSS article opening by routing it through main-process IPC guarded by an external URL policy (removing direct window.open usage in the renderer), while also improving the RSS reader UX and modernizing CI/release workflows.

Changes:

  • Add openRssArticle to the RSS facade/preload layer and use it from RssReaderView instead of window.open.
  • Add an inline unread-only “已读” action in the RSS reader list.
  • Extend external URL policy + IPC handlers/tests for RSS article opening; upgrade GitHub Actions runtimes and update the OAuth setup guide.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/renderer/src/views/RssReaderView.vue Uses openRssArticle for opening links; adds unread-only inline “已读” action.
src/renderer/src/views/RssReaderView.facade.test.mjs Updates facade contract assertions to include openRssArticle and no window.open.
src/renderer/src/styles.css Adds small layout/styles for RSS post row and “已读” button.
src/renderer/src/composables/useRssActions.mjs Adds openRssArticle action with URL assertion and forwards to API.
src/renderer/src/composables/useRssActions.test.mjs Covers openRssArticle contract and validates missing-url rejection.
src/main/preload.js Exposes openRssArticle via IPC channel rss:openArticle.
src/main/preload.test.js Verifies preload routes rss:openArticle and exposes openRssArticle.
src/main/policies/externalUrlPolicy.js Adds rssArticle rule allowing http:/https:.
src/main/policies/externalUrlPolicy.test.js Tests RSS article rule protocol allowance + credential rejection.
src/main/ipc/rssIpc.js Adds rss:openArticle IPC handler that validates URL policy and calls shell.openExternal.
src/main/ipc/rssIpc.test.js Tests allow/deny behavior for rss:openArticle guard and open call.
src/main/ipc.js Wires RSS open handler with evaluateExternalUrl, shell.openExternal, and EXTERNAL_URL_RULES.rssArticle.
docs/guides/github-oauth-app-setup.md Rewrites OAuth setup guide with explicit Device Flow requirements.
.github/workflows/ci.yml Upgrades actions and Node runtime; sets Node24 actions env flag.
.github/workflows/release-windows.yml Upgrades actions and Node runtime; sets Node24 actions env flag.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +137 to +151
async function openPost(subscription, post) {
if (!post?.link) {
message.value = "该文章缺少可打开的链接。";
return;
}

try {
await openRssArticle({ url: post.link });
} catch (error) {
message.value = `打开文章失败:${String(error?.message || error)}`;
return;
}

await markPostAsRead(subscription, post);
}

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

openPost now sets message on failures, but it never clears message on success. This can leave a previous “打开文章失败…” message visible even after a later click successfully opens an article. Consider clearing message.value before attempting to open (or after a successful open) so the UI reflects the latest action.

Copilot uses AI. Check for mistakes.
Comment thread src/main/ipc/rssIpc.js
});
ipcMain.handle('rss:openArticle', async (_event, payload) => {
const decision = evaluateExternalUrl(payload?.url, externalUrlRule);
if (!decision.allowed) {

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rss:openArticle throws the same “外部链接不受信任” error for all failures, including malformed URLs where evaluateExternalUrl returns reason: 'INVALID_URL'. That produces confusing renderer messages like “外部链接不受信任:INVALID_URL” for a feed item with a bad link. Consider special-casing INVALID_URL (and possibly SCHEME_NOT_ALLOWED) to throw a clearer error (e.g., “链接格式无效”) so users can distinguish an invalid link from a blocked/untrusted one.

Suggested change
if (!decision.allowed) {
if (!decision.allowed) {
if (decision.reason === 'INVALID_URL') {
throw new Error('链接格式无效');
}
if (decision.reason === 'SCHEME_NOT_ALLOWED') {
throw new Error('链接协议不被允许');
}

Copilot uses AI. Check for mistakes.
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.

2 participants