Skip to content

Stop logging auth payloads; stop prerendering image URLs - #240

Merged
Jan0707 merged 8 commits into
mainfrom
fix-token-logging-and-prerender
Aug 4, 2026
Merged

Stop logging auth payloads; stop prerendering image URLs#240
Jan0707 merged 8 commits into
mainfrom
fix-token-logging-and-prerender

Conversation

@Jan0707

@Jan0707 Jan0707 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Two small unrelated backlog items, as requested. Both measured rather than asserted, and both corrected a claim I'd made earlier.

1. Auth logging in the browser console

getCurrentUser() logged the result of directus.refresh() — a payload whose type is { access_token, refresh_token, expires, expires_at } — and the readMe() result, which carries the account's email and role. Both calls run in the browser. registerNewUser logged the created user; login-callback.vue logged the user object again.

One correction to what I told you. I said this "logs tokens". I can only partly substantiate that:

status
The user object (email, role) reaching the console confirmed
access_token / refresh_token reaching the console unconfirmed

The app uses authentication('session'), where Directus keeps the token in an httpOnly cookie, and the SDK just returns whatever /auth/refresh responds with. Directus's own docs don't document the session-mode response body, and I can't observe it without authenticating. So the token fields may well be null in practice.

I'd rather state that plainly than let a security-framed PR rest on something I didn't verify. It doesn't change the conclusion — there's no reason to print any of it, and the same line would print both tokens if the app ever moved to json mode.

Error logs now go through a small toLogMessage(), because the SDK rejects with a RequestError carrying the raw Response and the request that produced it — logging the object itself puts request details in front of the user.

A repo-wide sweep for console.* carrying token|auth|refresh|password|secret|user|session|login|credential now returns only two console.debug calls with static strings and no data.

2. nitro.prerender.ignore: ['/_ipx']

The plan said a full local build "currently fails". That was right, but not in the way it described — it's intermittent, which is why my first attempt today passed and made me doubt the note. Measured on full local builds of the same commit:

without ignore with ignore
result exit 1 (an earlier run passed) exit 0
duration 193s 29s
_ipx files 1475 (~100 MB) 0
prerendered HTML routes 44 44
[directus] retry warnings up to 4 0

The failure is ERROR terminated from undici — connection exhaustion — hitting prerender.failOnError. The retry wrapper added in an earlier phase is what lets it sometimes survive, which explains the flakiness.

Nothing consumes those files: Vercel serves images through _vercel/image and doesn't prerender, and CI builds with SKIP_PRERENDER_ROUTE_DISCOVERY=true so it never crawls. So this was 100 MB and ~164 seconds of pure waste, plus enough CMS load to trigger retries.

Verified /_ipx still works at runtime, since the handler stays in the server bundle:

GET /_ipx/f_png&q_80&fit_cover&s_468x312/https://admin.programmier.bar/assets/85cf…
→ HTTP 200, image/png, 52358 bytes
→ PNG image data, 468 x 312, 8-bit colormap

Verification

gate result
lint 0 errors, 128 warnings (unchanged)
test 67/67
ratchet 263 (unchanged)
full npm run build exit 0, 44 routes, 0 _ipx files
/login-callback HTTP 200

composables/useDirectus.ts stays prettier-dirty exactly as it is on main — formatting it would reindent its whole import block, which doesn't belong here. My additions match the surrounding style.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JkKMceYAzAYLrSyC42FWTf

Two small unrelated fixes, both from the post-plan backlog.

getCurrentUser() logged the result of directus.refresh(), whose payload
type carries access_token and refresh_token, and the readMe() result,
which carries the account's email and role. Both calls run in the browser,
so both went to the visitor's console. registerNewUser logged the created
user, and login-callback.vue logged the user object again.

Whether the token fields are actually populated depends on the auth mode:
the app uses authentication('session'), where Directus keeps the token in
an httpOnly cookie, and I could not verify the session-mode response shape
without authenticating. So the confirmed leak is the user object; the token
exposure is unconfirmed but is what the payload type describes, and would
become real if the app ever switched to json mode. Either way there is no
reason to print any of it.

Error logs now pass through toLogMessage(), since the SDK rejects with a
RequestError carrying the raw Response and its request.

Separately, nitro.prerender.ignore: ['/_ipx'] stops the crawler resizing
every <nuxt-img> variant it finds. Measured on a full local build:

                     without        with
  result             exit 1         exit 0
  duration           193s           29s
  _ipx files         1475 (~100MB)  0
  prerendered html   44             44

The failure is `ERROR terminated` from undici -- connection exhaustion --
hitting prerender.failOnError. It is intermittent: an earlier run of the
same commit passed in 193s, which is why the plan recorded this as always
failing. Nothing consumes those files: Vercel serves images through
_vercel/image and does not prerender. Verified /_ipx still serves at
runtime, returning a real 468x312 PNG.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JkKMceYAzAYLrSyC42FWTf
Copilot AI lite review requested due to automatic review settings August 4, 2026 09:08
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
programmierbar-website Ready Ready Preview Aug 4, 2026 11:19am

Request Review

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1edd2f2062

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread nuxt-app/nuxt.config.ts Outdated
// finds — 1476 files and ~100 MB from 44 routes — and hammer the CMS while doing it. Nothing
// consumes them: Vercel serves images through `_vercel/image` and does not prerender, and
// `/_ipx` still works at runtime because the handler stays in the server bundle.
ignore: ['/_ipx'],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve IPX outputs during static generation

When the supported npm run generate command is used, the output has no Nitro server to handle /_ipx requests at runtime, so the crawler-generated IPX files are what make <nuxt-img> URLs work in the static deployment. Ignoring this prefix unconditionally removes those files while leaving the generated HTML pointed at them, causing optimized images to return 404; restrict the ignore rule to server/Vercel builds or otherwise retain IPX generation for the static preset.

AGENTS.md reference: AGENTS.md:L42-L49

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're right, and this would have been a bad one to ship. Fixed in f03ffa9.

The mistake was in what I verified. I checked that /_ipx still resolves after the change — it does, and I have a 200 with a real PNG to prove it. But that only holds for nuxt build, which produces a server. For nuxt generate the crawler's output is the thing serving those URLs, so "the handler is still in the bundle" was answering a question nobody asked.

The evidence was in my own output and I walked past it. I reported "44 HTML routes unchanged, nothing lost" while those files were full of references to what I'd just deleted:

file /_ipx/ references files on disk after the change
index.html 73 0
podcast/index.html 253 0
meetup/index.html 143 0

The fix

Scoped with the framework's own signal rather than an env-var guess. nuxi generate is nuxi build with nitro: { static: ctx.args.prerender } — confirmed in @nuxt/cli/dist/build-*.mjs — so nitroConfig.static distinguishes them exactly:

if (!nitroConfig.static) {
    nitroConfig.prerender ??= {}
    nitroConfig.prerender.ignore ??= []
    nitroConfig.prerender.ignore.push('/_ipx')
}

Both paths verified this time, which is what I should have done originally:

result duration _ipx files html server
npm run build exit 0 29s 0 44 present
npm run generate exit 1 809s 6180 414 absent

So the static path keeps its images, and the server path keeps the 193s → 29s saving.

One thing your comment surfaced by accident

npm run generate still fails, but not for this reason and not because of this PR — the crawler follows two schemeless URLs in CMS speaker records as if they were relative paths:

[404] Page not found: /hall-of-fame/www.linkedin.com/in/mariekilg/
[404] Page not found: /konferenz/www.linkedin.com/in/mariekilg/
marie-kilg      linkedin_url = "www.linkedin.com/in/mariekilg/"
andre-neubauer  twitter_url  = "twitter.com/devpg"

These are live user-facing bugs, not just build ones. Production serves the hrefs verbatim, so a visitor clicking either link resolves it against the current page:

GET https://www.programmier.bar/hall-of-fame/www.linkedin.com/in/mariekilg/ → 404

Two speakers' social links have been going to a 404 instead of LinkedIn and Twitter. The prerender crawler was effectively acting as a link checker. Logged for the maintainer rather than folded into this PR — the durable fix is probably to normalise a missing scheme in the component, since CMS data will drift again.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 addresses two operational issues in the Nuxt app: (1) removing sensitive/unnecessary auth-related logging in browser-executed code paths, and (2) preventing Nitro prerender from crawling and generating _ipx image variants during prerender route discovery to avoid flaky builds and wasted work.

Changes:

  • Removed client-side console logging of user/auth-related data during login callback flow.
  • Introduced a small toLogMessage() helper and stopped logging auth payloads/user objects inside useDirectus() auth helpers.
  • Configured Nitro prerender to ignore /_ipx to prevent prerender from fetching/resizing image variants.

Reviewed changes

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

File Description
nuxt-app/pages/login-callback.vue Removes logging of the current user object in the browser on mount.
nuxt-app/nuxt.config.ts Adds Nitro prerender ignore rule for /_ipx to avoid prerender crawling image URLs.
nuxt-app/composables/useDirectus.ts Stops logging auth payloads/user objects; adds a helper to sanitize error logging.

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

Comment thread nuxt-app/composables/useDirectus.ts
Comment thread nuxt-app/composables/useDirectus.ts
The reviewer was right and I had verified the wrong thing. I checked that
/_ipx still resolves at runtime, which is true for `nuxt build` -- but
`nuxt generate` produces no server, so there the crawler's output IS what
serves those URLs. The prerendered HTML is full of them: 73 references in
index.html, 253 in podcast/index.html, 143 in meetup/index.html. Ignoring
the prefix unconditionally would have shipped a static site whose every
optimised image 404s.

The ignore now applies only when nitro.static is false. That is the
framework's own signal: nuxi generate is nuxi build with
`nitro: { static: ctx.args.prerender }`, confirmed in @nuxt/cli.

Verified both paths this time:

  npm run build     exit 0,  29s, 0 _ipx files,    44 html, server present
  npm run generate  exit 1, 809s, 6180 _ipx files, 414 html, server absent

generate's failure is pre-existing and unrelated -- the crawler follows two
schemeless URLs in CMS speaker records as relative paths:

  [404] Page not found: /hall-of-fame/www.linkedin.com/in/mariekilg/

  marie-kilg      linkedin_url = "www.linkedin.com/in/mariekilg/"
  andre-neubauer  twitter_url  = "twitter.com/devpg"

Those are also live user-facing bugs: production serves the hrefs verbatim,
so both links resolve against the current page and return 404 instead of
going to LinkedIn or Twitter. Logged, not fixed here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JkKMceYAzAYLrSyC42FWTf

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

…site

A schemeless value in an href is resolved against the current page, so
`www.linkedin.com/in/mariekilg/` became
`/hall-of-fame/www.linkedin.com/in/mariekilg/` -- a 404 on our own domain
for the visitor, and a build failure for `npm run generate`, whose crawler
follows it.

normalizeExternalUrl() runs every platform URL through one chokepoint,
`platformList` in IndividualPlatforms.vue, which already funnels all eight
fields for both speakers and members.

The CMS holds three shapes, and they need different answers:

  https://www.linkedin.com/in/x  absolute            -> unchanged
  www.linkedin.com/in/x          schemeless URL      -> https:// prefixed
  @jSchaback                     a handle, not a URL -> link omitted

A handle is dropped rather than guessed at: deriving a profile URL from it
needs to know the platform, and a wrong guess is a link that looks fine and
goes nowhere. The existing `.filter(platform => platform.url)` already drops
the entry, so no icon is rendered.

One case is deliberately not solved: a bare username containing a dot
(`t.muelleer`) is indistinguishable from a bare domain (`example.com`),
which is a legitimate website_url. It becomes https://t.muelleer and fails
to resolve. The point is that a bad link now leaves our domain and fails as
somebody else's problem instead of rendering a 404 that looks like ours.

Verified on the four previously affected speaker pages: 0 schemeless hrefs,
the handle link gone, the username link absolute.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JkKMceYAzAYLrSyC42FWTf

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

nuxt-app/test/normalizeExternalUrl.test.ts:19

  • Tests cover schemeless domains, but they currently don’t assert that unsafe absolute schemes (e.g. javascript: / data:) are dropped. Adding this locks in the "safe to put in an href" contract and prevents regressions that could reintroduce XSS vectors.
    it('leaves an absolute URL alone', () => {
        expect(normalizeExternalUrl('https://www.linkedin.com/in/claudiaplattner')).toBe(
            'https://www.linkedin.com/in/claudiaplattner'
        )
        expect(normalizeExternalUrl('http://example.com')).toBe('http://example.com')
        expect(normalizeExternalUrl('mailto:hallo@programmier.bar')).toBe('mailto:hallo@programmier.bar')
        expect(normalizeExternalUrl('//cdn.example.com/x')).toBe('//cdn.example.com/x')
    })

Comment thread nuxt-app/helpers/normalizeExternalUrl.ts Outdated
…text

normalizeExternalUrl takes a kind: 'web' (default), 'twitter', 'instagram',
'linkedin', 'github', 'youtube', 'bluesky' or 'mastodon'. Knowing the
platform is what makes a handle resolvable -- and it settles a case the
previous version could not:

  @jSchaback   twitter    -> https://twitter.com/jSchaback
  t.muelleer   instagram  -> https://www.instagram.com/t.muelleer

`t.muelleer` reads like a hostname but is a valid Instagram username, and
only the field it came from can say which was meant. Bluesky makes the same
point more sharply: its handles *are* domains.

Mastodon splits user from instance (`@a@b.social` -> https://b.social/@a)
and is dropped when the instance is missing, since it cannot be guessed.
YouTube re-adds the `@` its URLs require; the others strip it.

A second surface turned up while verifying: `npm run generate` still failed
on a schemeless href *inside* CMS rich text, which the platform fields
never see:

  speakers | stefan-tilkov | description | href="innoq.com/de/staff/..."

So sanitizeHtml now normalises href and src in an afterSanitizeAttributes
hook. That runs after DOMPurify has removed unsafe URLs, so a javascript:
href is gone before the hook sees the node and only approved values are
rewritten -- covered by a test. Root-relative links are left alone, so
internal links in rich text keep working.

Verified on a real build: all three values now absolute, 0 schemeless hrefs
on the three affected speaker pages, and the internal /podcast/... link in
stefan-tilkov's biography untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JkKMceYAzAYLrSyC42FWTf

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

nuxt-app/helpers/normalizeExternalUrl.ts:92

  • normalizeExternalUrl currently returns any absolute URL unchanged, including javascript:/vbscript:. Since this helper is used directly for :href values (e.g. speaker social links), a malicious CMS value could become a clickable script URL. Please explicitly reject dangerous schemes before returning absolute URLs.
    // Already absolute (`https:`, `mailto:`), protocol-relative, or deliberately site-internal.
    if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed) || trimmed.startsWith('//') || trimmed.startsWith('/')) {
        return trimmed
    }

Comment thread nuxt-app/test/normalizeExternalUrl.test.ts
@Jan0707

Jan0707 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

npm run generate — the link fixes worked, and revealed the real blocker

Three full generate runs, one per fix. Each removed a blocker and exposed the next:

run 404s from crawled links html failed on
ipx scoping only 2 (schemeless LinkedIn) 414 crawled 404
+ platform-field normalisation 2 (schemeless innoq.com in rich text) 237 crawled 404
+ rich-text href hook 0 413 ipx [500]

So the link work is done — zero crawled 404s — but generate still exits 1:

Errors prerendering:
  ├─ /_ipx/…/assets/a01e049d-… (10380ms)
  │ ├── [500]
  │ └── Linked from /podcast/deep-dive-207-passkeys-mit-martina-kraus

ERROR  fetch failed
    at async fetchURL (node_modules/ipx/…)

This is the problem this PR started from, seen from the other side. generate attempts 6183 image fetches, each one a download from Directus plus a sharp resize. The CMS degrades under it — slowest responses in that run:

169s, 194s, 210s, 245s, 292s

Then ipx gives up with a 500 and failOnError ends the build.

That is exactly why prerender.ignore: ['/_ipx'] exists for nuxt build. And per your review it cannot apply to generate, because there the files are the image pipeline. Those two facts together mean npm run generate is not completable against this CMS at this scale — not because of anything in this PR, and not newly: it was already failing on main, just earlier, at the 404s.

What I'm not doing here

I'm not chasing it in this PR. It's a capacity problem, not a link problem, and the fixes for it are all bigger decisions:

  • lower nitro.prerender.concurrency so the CMS isn't hit 8-deep, trading a slow build for a completable one;
  • cache originals locally so 6183 fetches become ~500;
  • or decide generate isn't a supported path and drop the script plus its AGENTS.md line.

That last one is a call for you, not me — nothing in CI or on Vercel uses generate, and Vercel serves images through _vercel/image regardless, so it may be a documented command that no longer has a purpose.

I've also stopped re-running it. Three runs at ~13.5 minutes each is enough evidence, and each one puts real load on your production CMS.

This PR's own verification is unaffected

gate result
lint 0 errors, 128 warnings
test 88/88
ratchet 263
npm run build (full, no skip flag) exit 0, 29s, 0 _ipx, 44 routes
rendered links 3 fixed values absolute, 0 schemeless hrefs, internal /podcast/… preserved

`npm run generate` cannot finish against this CMS. A static build has to
prerender every <nuxt-img> variant -- 6183 downloads and resizes -- and the
CMS degrades under it until ipx returns 500 and failOnError ends the build.
Measured response times late in a run: 169s, 194s, 210s, 245s, 292s.

Nothing depended on it. No workflow or Vercel config invokes it, Vercel runs
nuxt build, and images there are served by _vercel/image rather than ipx.
It was already failing on main, just earlier, on schemeless links.

AGENTS.md now records the absence and why, so the script is not reinstated
as an oversight.

The `nitro.static` guard in nuxt.config.ts stays. `npx nuxi generate` still
works without the script, sets nitro.static, and produces no server -- so
without the guard it would silently 404 every optimised image rather than
fail loudly. Comment updated to say that, since the obvious reading now is
that the guard is dead code.

Also drops two comment references to the removed script; the reason the URL
normalisation matters is the visitor-facing 404, which stands on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JkKMceYAzAYLrSyC42FWTf

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (2)

nuxt-app/test/normalizeExternalUrl.test.ts:21

  • Add a regression test that absolute-but-unsafe schemes (e.g. javascript:) are dropped. This ensures the helper can safely be used for CMS-provided social/website links (e.g. in IndividualPlatforms.vue).
        it('leaves an absolute URL alone', () => {

nuxt-app/helpers/normalizeExternalUrl.ts:92

  • normalizeExternalUrl currently treats any absolute scheme as safe and returns it unchanged. This allows javascript:, data:, etc. to flow into href (e.g. in IndividualPlatforms.vue), which is not safe for untrusted CMS input. Consider allow-listing safe schemes (http/https/mailto/tel) and returning undefined for everything else.
    // Already absolute (`https:`, `mailto:`), protocol-relative, or deliberately site-internal.
    if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed) || trimmed.startsWith('//') || trimmed.startsWith('/')) {
        return trimmed
    }

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 4, 2026 11:10
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (1)

nuxt-app/helpers/normalizeExternalUrl.ts:111

  • normalizeExternalUrl() treats schemeless URLs as URLs only if they contain a / path segment. Inputs like twitter.com?x=1 or twitter.com#frag are still clearly URLs (not handles), but currently fall through to the handle branch for social kinds and can become https://twitter.com/twitter.com?x=1 etc. Consider treating ?/# as URL indicators as well.
    if (rules.hosts.includes(host) || (host.includes('.') && trimmed.includes('/'))) {
        return `https://${trimmed}`
    }

The allowlist itself is a real improvement and stays: a `javascript:` value
in a CMS field is now dropped instead of returned unchanged. It just did not
compile here.

  helpers/normalizeExternalUrl.ts(92,24): error TS2532: Object is possibly 'undefined'
  Typecheck regression: 264 errors, baseline is 263 (+1)

`match()[1]` is `string | undefined` under noUncheckedIndexedAccess, which is
Nuxt 4's default and which Phase 4 deliberately kept. Rewritten as two regex
tests, so there is no array index to narrow and the semantics are unchanged.

Also closes a latent regression the allowlist introduced in combination with
the sanitize hook. The hook ran normalizeExternalUrl over every href and src,
so once non-allowlisted schemes started returning undefined it would have
stripped inline `data:` images, which DOMPurify legitimately permits. The
hook now only fills in a *missing* scheme and leaves existing ones to
DOMPurify's URI policy. No live content is affected -- 880 rich-text values
scanned, none with a scheme outside the allowlist -- so this is prevention.

Both behaviours now have tests, including the host-with-a-port case
(`example.com:8080/x`), which is indistinguishable from a scheme and is
dropped. That is a documented decision rather than an accident.

Re-verified after the change: the schemeless rich-text link, both handles,
and 0 schemeless hrefs across the three affected pages.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JkKMceYAzAYLrSyC42FWTf
Copilot AI review requested due to automatic review settings August 4, 2026 11:18
@Jan0707
Jan0707 merged commit 3db0102 into main Aug 4, 2026
6 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (1)

nuxt-app/helpers/normalizeExternalUrl.ts:56

  • In the Mastodon rules, handle.split('@') will happily accept handles with more than one @ (e.g. user@instance@extra) and silently ignore everything after the second segment due to array destructuring. That can produce incorrect outbound URLs for malformed CMS input; it’s safer to reject anything that isn’t exactly user@instance (and ideally disallow path/query chars in either part).
        profileUrl: (handle) => {
            const [user, instance] = handle.split('@')
            return user && instance ? `https://${instance}/@${user}` : undefined
        },

Jan0707 added a commit that referenced this pull request Aug 4, 2026
Rebased onto main now that #240 has merged, and amended for everything it
changed. Addresses the review comment on this PR plus three other items that
had gone stale.

The reviewer's point: the verification paragraph still pointed at
test/getPlainText.test.ts, which no longer exists -- the tests moved to
test/sanitize.test.ts when the DOMPurify policy was consolidated -- and the
"5 cases" count predated that. Now 18 cases across the three exports, with a
note that the danger check is itself tested against unsanitised input, since
its first version passed vacuously.

Also:

  - The /_ipx follow-up is done. Corrects this document's own description of
    the failure: it said "currently fails" when it fails *intermittently*,
    which is why one reproduction attempt passed and the next did not.
    Records the guard on nitro.static as load-bearing, including why it stays
    now that the generate script is gone.
  - Static generation dropped, with the capacity numbers that decided it.
  - The two "known issues" entries that still described the local build as
    broken.
  - Five decision-log rows for #240, including the two places where checking
    changed a claim: the token exposure is unconfirmed rather than confirmed,
    and the first ignore rule was verified against the wrong mechanism.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JkKMceYAzAYLrSyC42FWTf
@Jan0707
Jan0707 deleted the fix-token-logging-and-prerender branch August 4, 2026 11:40
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