Skip to content

Add circular redirect detection to linter - #12

Merged
jamengual merged 2 commits into
mainfrom
feature/circular-redirect-detection
Feb 17, 2026
Merged

Add circular redirect detection to linter#12
jamengual merged 2 commits into
mainfrom
feature/circular-redirect-detection

Conversation

@jamengual

Copy link
Copy Markdown
Owner

Summary

  • Circular redirect detection in the linter via graph-based DFS cycle detection — catches direct cycles, transitive chains, prefix self-loops, cross-host cycles, and regex/glob sample-based tracing
  • Enriched webhook response — lint failures return HTTP 422 with structured JSON containing all issues instead of a generic "Sync failed", enabling CI pipelines to parse and surface specific feedback
  • Comprehensive documentation — detection types, worked examples with colored output, JSON/CI usage, webhook response format, and limitations table

What's Changed

Lint: Circular Redirect Detection (internal/lint/lint.go)

New checkCircularRedirects() builds a directed graph from redirect rules and runs DFS with three-color marking to find cycles:

Detection Severity Example
Direct cycle (A→B→A) Error /a → /b, /b → /a
Transitive cycle (A→B→C→A) Error /a → /b → /c → /a
Prefix cross-cycle Error /foo/ → /bar/, /bar/ → /foo/
Cross-host cycle Error example.com/p1 → example.com/p2 → …/p1
Prefix self-loop (preserve_path) Error /old/ → /old/new/ expands infinitely
Regex self-match Warning ^/api/v1/(.*) → /api/v1/v2/$1 (sample-based)
Glob loop Warning Glob destination falls within same match (sample-based)

Supporting functions: buildRedirectGraph, findCycles, extractDestinationPath, checkPrefixSelfLoops, checkRegexGlobCycles, generateRegexSamples/generateGlobSamples.

Webhook: Structured Lint Error Response (cmd/redirector-sync/main.go)

  • New LintError type carries the full lint.Result
  • SyncOnce() returns *LintError on lint failures (instead of fmt.Errorf)
  • Webhook handler uses errors.As to detect lint failures and returns HTTP 422 with JSON:
{
  "status": "lint_failed",
  "source": "github-primary",
  "message": "lint errors found in config from source github-primary (1 errors)",
  "issues": [
    {
      "severity": "error",
      "rule_id": "old-home",
      "message": "Circular redirect detected: old-home -> new-home -> old-home",
      "suggestion": "Remove one rule from the chain or change a destination to break the cycle"
    }
  ]
}

Documentation

  • docs/SYNCER.md — New "Circular Redirect Detection" section with graph diagram, detection table, 4 worked examples (direct cycle, prefix self-loop, regex warning, JSON for CI), webhook response format, and limitations table
  • docs/FEATURES.md — Added circular redirect detection to lint checks list
  • docs/MANAGEMENT_API.md — Documented webhook response format (success/422/500)
  • IMPLEMENTATION_PLAN.md — Phase 9 plan with Stage 9.1 marked complete

Tests (internal/lint/lint_test.go)

10 new tests covering all detection scenarios:

  • TestLinter_CheckCircularRedirects_DirectCycle
  • TestLinter_CheckCircularRedirects_TransitiveCycle
  • TestLinter_CheckCircularRedirects_NoCycle
  • TestLinter_CheckCircularRedirects_ExternalDestination
  • TestLinter_CheckCircularRedirects_CrossHostCycle
  • TestLinter_CheckCircularRedirects_PrefixSelfLoop
  • TestLinter_CheckCircularRedirects_PrefixNoSelfLoop
  • TestLinter_CheckCircularRedirects_NonRedirectSkipped
  • TestLinter_CheckCircularRedirects_PrefixCrossCycle
  • TestLinter_CheckCircularRedirects_RegexSelfCycle

Test plan

  • All 10 circular redirect detection tests pass
  • All 25 lint tests pass (no regressions)
  • Full project test suite passes (go test ./...)
  • golangci-lint run ./internal/lint/ — 0 issues
  • go build ./... — compiles clean
  • Manual test: create config with circular redirect, run redirector-sync --lint --lint-config config.yaml
  • Manual test: trigger webhook with circular config, verify HTTP 422 response

🤖 Generated with Claude Code

jamengual and others added 2 commits February 15, 2026 23:11
Detect redirect loops at config-lint time using graph-based DFS cycle
detection. The linter builds a directed graph from redirect rules and
finds cycles with three-color marking. Exact and prefix rules produce
error-severity findings; regex/glob rules use sample-based tracing and
produce warnings (best-effort).

Detection covers: direct cycles (A->B->A), transitive chains
(A->B->C->A), prefix cross-cycles, cross-host cycles via absolute
URLs, prefix self-loops with preserve_path, and regex/glob
self-matching destinations.

Also enrich the syncer webhook response: lint failures now return
HTTP 422 with a structured JSON body containing all issues (severity,
rule_id, message, suggestion) instead of a generic "Sync failed".
This lets CI pipelines parse the response and provide specific
feedback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jamengual
jamengual merged commit a08f67a into main Feb 17, 2026
9 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