Skip to content

Redirect the Oullin writing archive - #195

Merged
gocanto merged 2 commits into
mainfrom
feat/redirect-writing-archive
Jul 27, 2026
Merged

Redirect the Oullin writing archive#195
gocanto merged 2 commits into
mainfrom
feat/redirect-writing-archive

Conversation

@gocanto

@gocanto gocanto commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

What changed

  • added an exact permanent redirect for each of the 24 former Oullin post URLs
  • preserved the malformed legacy engineering-management .md path while sending it to the clean Gocanto route
  • redirected /writing, /writing/, and /tags/* to the Gocanto Writing index
  • kept the redirects ahead of protected-path and default proxy handlers
  • deliberately avoided a broad /post/* rule
  • added table-driven coverage for every source/target pair and handler placement

Rollout

The complete Gocanto archive is already live and every destination HTML and raw Markdown route has been verified with status 200. Merging this pull request activates the public cutover through the existing VPS deployment workflow.

Validation

  • go test ./infra/caddy
  • make caddy-validate with generated scratch mTLS certificates
  • production verification of all 24 Gocanto HTML routes and 24 raw Markdown routes

Summary by CodeRabbit

  • New Features
    • Added permanent (301) redirects for legacy writing post URLs to their canonical pages.
    • Added redirects for /writing, /writing/, and /tags/* to the writing archive.
  • Bug Fixes
    • Ensured writing archive redirects are applied before the site’s default routing.
  • Tests
    • Added production Caddyfile coverage to verify redirect presence and ordering before the default proxy.

@gocanto
gocanto marked this pull request as ready for review July 27, 2026 08:46
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The production Caddyfile adds permanent redirects for legacy writing URLs to writing.gocanto.sh. A new test verifies exact destinations, ordering before the default proxy, and the absence of a broad post redirect.

Changes

Writing archive redirects

Layer / File(s) Summary
Archive redirect routing and validation
infra/caddy/Caddyfile.prod, infra/caddy/caddyfile_prod_test.go
Adds exact 301 redirects for legacy post URLs and broader writing archive paths, and tests that these rules precede the default proxy without using a broad /post/* redirect.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly states the main change: adding redirects for the Oullin writing archive.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@infra/caddy/caddyfile_prod_test.go`:
- Around line 206-214: Update the archive redirect assertions in the directive
loop to validate each directive’s placement within oullinBlock, not just its
presence. Reuse the existing position-checking approach used elsewhere in the
test and apply it to all three archive redirects, preserving the current
expected order relative to the default proxy.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 27a8f9fb-ba7c-4899-a5e4-e6b043ba9dce

📥 Commits

Reviewing files that changed from the base of the PR and between 24e8b72 and d76e7a7.

📒 Files selected for processing (2)
  • infra/caddy/Caddyfile.prod
  • infra/caddy/caddyfile_prod_test.go

Comment thread infra/caddy/caddyfile_prod_test.go
@gocanto
gocanto force-pushed the feat/redirect-writing-archive branch from f56eed1 to d553658 Compare July 27, 2026 09:05

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@infra/caddy/caddyfile_prod_test.go`:
- Around line 220-222: Update the redirect validation in the relevant test to
reject any wildcarded /post source, including /post* and equivalent named
matchers, rather than checking only the literal “redir /post/*” string. Preserve
acceptance of non-broad /post routes while ensuring /post, /post/, and subpaths
cannot be covered by a wildcard matcher.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: dff64cca-3cbd-483f-9bd2-2a8c9671d5de

📥 Commits

Reviewing files that changed from the base of the PR and between f56eed1 and d553658.

📒 Files selected for processing (2)
  • infra/caddy/Caddyfile.prod
  • infra/caddy/caddyfile_prod_test.go

Comment on lines +220 to +222
if strings.Contains(oullinBlock, "redir /post/*") {
t.Fatal("must not use a broad /post/* redirect")
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

set -euo pipefail
git ls-files infra/caddy/caddyfile_prod_test.go
echo '---'
ast-grep outline infra/caddy/caddyfile_prod_test.go --view expanded
echo '---'
sed -n '180,250p' infra/caddy/caddyfile_prod_test.go

Repository: oullin/api

Length of output: 2793


🏁 Script executed:

set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p = Path('infra/caddy/caddyfile_prod_test.go')
text = p.read_text()
for needle in ['redir /post/*', 'strings.Contains(oullinBlock', 'named matcher', '/post*']:
    print(f'### {needle}')
    for i, line in enumerate(text.splitlines(), 1):
        if needle in line:
            print(i, line)
PY

Repository: oullin/api

Length of output: 342


🏁 Script executed:

set -euo pipefail
# Inspect the caddy matcher docs snippet locally in case the repo vendors a reference or comment.
rg -n "redir /post\\*|/post/\\*|matcher" infra/caddy -S

Repository: oullin/api

Length of output: 550


🏁 Script executed:

set -euo pipefail
python3 - <<'PY'
from pathlib import Path
p = Path('infra/caddy/caddyfile_prod_test.go')
for i, line in enumerate(p.read_text().splitlines(), 1):
    if 205 <= i <= 235:
        print(f"{i:4d}: {line}")
PY

Repository: oullin/api

Length of output: 826


🏁 Script executed:

set -euo pipefail
# Inspect the production Caddyfile and any related redirect definitions.
git ls-files infra/caddy
echo '---'
rg -n "redir /post|`@post`|/post\\*" infra/caddy -S
echo '---'
# Show the relevant production block if present.
python3 - <<'PY'
from pathlib import Path
for path in [Path('infra/caddy/Caddyfile'), Path('infra/caddy/caddyfile_prod_test.go')]:
    if path.exists():
        print(f'## {path}')
        for i, line in enumerate(path.read_text().splitlines(), 1):
            if 1 <= i <= 260 and ('/post' in line or 'redir' in line or '`@post`' in line or 'reverse_proxy' in line):
                print(f"{i:4d}: {line}")
PY

Repository: oullin/api

Length of output: 8925


🌐 Web query:

Caddy path matcher /post* /post/* matcher docs redir shortcut directive

💡 Result:

In Caddy, path matching is exact by default [1][2]. To match a path prefix, you must append an asterisk () [1][3][2]. Understanding the difference between /post and /post/* is critical [1][3]: - /post* matches /post, /post/, /postbar, and /post/bar [1][3]. - /post/* matches /post/ and /post/bar, but does NOT match /post or /postbar [1][3]. For most use cases where you want to match a path and all its sub-paths (e.g., to redirect a directory), /post/* is generally the preferred and more predictable choice [1][3][4]. The redir directive is used to issue HTTP redirects [5][6]. It accepts an optional matcher and the target location [5][7]. Common patterns: To redirect a specific path and all its sub-paths to a new location while preserving the remaining URI: redir /post/* https://example.com/new-post{uri} To redirect everything: redir https://example.com{uri} If you are using handle_path, note that it implicitly strips the matched path prefix, which can simplify your configuration if you need to perform actions on the remaining path segment after the prefix [8]. Caddyfile directives are evaluated based on a specific order, and redir is placed very early in the request pipeline [5][6][9], meaning it will trigger before most other directives (like reverse_proxy) if it matches the request [5].

Citations:


🏁 Script executed:

set -euo pipefail
# Check whether the repository includes tests or docs that spell out the intended matcher shape.
rg -n "must not use a broad /post|broad /post|writing redirect|matcher" . -S

Repository: oullin/api

Length of output: 959


Reject broad /post matchers, not just redir /post/*. This check still misses redir /post* and equivalent named matchers, which would cover /post, /post/, and subpaths. Assert against wildcarded /post sources, not just the literal /post/*.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infra/caddy/caddyfile_prod_test.go` around lines 220 - 222, Update the
redirect validation in the relevant test to reject any wildcarded /post source,
including /post* and equivalent named matchers, rather than checking only the
literal “redir /post/*” string. Preserve acceptance of non-broad /post routes
while ensuring /post, /post/, and subpaths cannot be covered by a wildcard
matcher.

Source: MCP tools

@gocanto
gocanto merged commit cee9193 into main Jul 27, 2026
4 checks passed
@gocanto
gocanto deleted the feat/redirect-writing-archive branch July 27, 2026 09:09
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