Skip to content

Link URLs in the Console - #942

Merged
JacobStephens2 merged 4 commits into
mainfrom
issue-918
Oct 21, 2026
Merged

JacobStephens2 merged 4 commits into
mainfrom
issue-918

Conversation

@JacobStephens2

@JacobStephens2 JacobStephens2 commented Oct 21, 2026 •

Copy link
Copy Markdown
Owner

Closes #918

Summary

URLs that appear in Console text are now links. A new linkify filter escapes the text and turns each https:// URL in it into a link. The Inbox, History and Security pages, Command details, and Command and Session logs all use it.

 src/console/
+├── filters.rs        # linked(text): escape, link each https:// URL; `linkify` filter; escaped()
 ├── row.html          # pr, cause, Tickets, findings |linkify; subject → <a href=issue>
 ├── inbox.html        # references, idle Passes |linkify
 ├── peek.html         # "Pull request left" |linkify
 ├── fact.html         # every Command details fact |linkify
 └── conversation.rs   # log text linked; one escaper (local escape removed)
 src/logs/status/inbox.rs
+    Row.subject_url: Option<String>   # the issue's https:// address
linked(text)
  for each "https://" in text
    the URL ends at whitespace, < > " ' or `
    trailing . , ; : ! ? stay outside the link, as does a ")" the URL did not open
    escape(URL) inside <a href>; escape everything else

The issue's example row, after this change:

  • JacobStephens2/thirdshift#812 links to the issue.
  • https://github.com/.../pull/834 is a link.
  • In "PR https://github.com/.../pull/834 is a draft", the URL is a link.

Only https:// URLs become links, as Security findings already did, so javascript: and other schemes stay plain text.

Evidence

  • Before: the new urls_in_inbox_and_peek_text_are_links_and_other_text_stays_escaped failed against main. The PR, cause, subject, Ticket and Command details text were plain.
    After: it passes:
    GET /      contains <p class="pr"><a href="https://…/pull/834">https://…/pull/834</a></p>
               contains <p>PR <a href=…>…</a> is a draft. &#60;b&#62;javascript:alert(1)&#60;/b&#62;</p>
               contains <span class="subject"><a href="https://…/issues/812">acme/widgets#812</a></span>
    GET /peek  contains <dd><a href="https://…/pull/834">…</a></dd>
    
  • Before: the review's test keeps_a_closing_paren_that_belongs_to_the_url failed on the first commit: …Rust_(programming_language\">…</a>). After: it passes.
  • logs_inventory_matches_cli_and_reads_current_layout_only now asserts that the Command log and the Session log each contain an <a href> for their URL.
  • Full cargo test --locked: exit 0 (55 test binaries, 0 failed). That run was on c48b664.
  • After the escaper-only commit 63effe3, I ran targeted checks rather than the full suite again. All passed:
    • cargo test --locked --test console: 40 passed
    • cargo test --bin thirdshift console::: 9 passed
    • cargo clippy --all-targets: clean
    • node --test tests/logs.test.cjs: 4 passed
  • Console browser tests (npm test): 35/35 on the first commit. On a later run one timing-sensitive heartbeat test timed out while the machine's load average was about 20 on 4 cores. node --test tests/inbox.test.cjs then passed 22/22.

Merge Danger

Door: two-way

This only changes how text is rendered. No stored data or CLI output changes.

Blast Radius: markup

  • The .subject span now wraps an <a>. Browser tests that find rows by .subject text still pass.
  • Log text is escaped with numeric entities (&#60;) instead of &lt;. Browsers display both the same.

Unaddressed findings

Standards

  • Data clump: subject() and issue_url() take the same Option<&Issue> (src/logs/status/inbox.rs, subject_url: issue_url(facts.issue.as_ref())). Declined.
    • subject() is also used for Landing references, which need no URL.
    • Returning a struct from subject() would widen three call sites to save one helper.
    • The reviewer rated it minor.
  • Subject extraction in inbox_over_http_matches_status_and_embeds_only_local_resources assumes every subject is linked (tests/console.rs, .split("</a></span>")). Declined.
    • The reviewer called it a brittleness note, not a defect.
    • The test's expected already requires every fixture Command to have an issue, so each subject is linked.
  • Optional docs/code-navigation.md row for Inbox and peek rendering. Declined. The index has no row for Inbox or peek rendering today. The Logs row already names src/console/conversation.rs, the caller of the new module. The reviewer found no change required.

Spec

  • Still plain text: the Inbox Warning: line, issue titles, branch names in Command details, and Console log events. Declined.
    • The Warning: line is fixed text from src/logs/status/inbox.rs ("logs.waiting_line_minutes must be less than …") and holds no URL.
    • Branch names cannot be https:// URLs.
    • None of these surfaces appears in the issue's example. The reviewer judged them low impact and out of scope.

Security

  • None. The Security review found no vulnerability introduced by this change: link text and href go through askama's HTML escaper, only https:// URLs become links, and the Console already sends Referrer-Policy: same-origin.

Security review outcome

No unaddressed introduced findings.

Review coverage

Both reviewers read every changed file. There are no generated-output exclusions and no unread changed files.

🤖 Generated with Claude Code

Built with claude · claude-opus-5-5 · medium

JacobStephens2 and others added 4 commits October 21, 2026 11:09
A shared linkify filter escapes text and wraps each https:// URL in a
link: pull requests, causes, Tickets, references, idle Passes and the
Command details facts. Issue subjects link to their issue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The conversation renderer shares the linkify core, so URLs in Command and
Session logs are links too. A closing parenthesis the URL opened stays in
the link. Security finding links use the same filter, and a Row's issue
address is an Option set only for https URLs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Role and tool-name headings now use the same escaping as the linked log
text and the templates, instead of a second hand-written escaper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JacobStephens2
JacobStephens2 merged commit eb7a847 into main Oct 21, 2026
18 checks passed
@JacobStephens2
JacobStephens2 deleted the issue-918 branch October 21, 2026 16:51
@JacobStephens2 JacobStephens2 mentioned this pull request Oct 21, 2026
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.

make urls in thirdshift console web ui clickable links

1 participant