From ab497bf93ecc769f621b59220d9df1c13d3d2fa1 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 13 May 2026 19:46:51 +0000 Subject: doc-linter: handle absolute paths in is_docs_path() CodeRabbit review on 28224f3 flagged that is_docs_path() introduced in 65a8e9f only matched repo-relative path strings. An absolute path to docs/... (e.g., from a local invocation that pre-resolves paths, or from tooling that uses git ls-files --full-path) would silently fail the docs/ check and the file would be skipped. Rewrite the helper to use os.path.commonpath against an absolute docs/ root computed on each call. Both inputs are normalized to absolute form, so repo-relative and absolute callers produce the same result. ValueError from commonpath (mixed Windows drives or empty input) is caught and treated as 'not a docs path'. abs_docs is recomputed per call rather than captured at import time so the helper picks up the actual cwd at invocation, matching the existing assumption that CI / local runs invoke the linter from the repo root. Verified against 12 edge cases: - repo-relative docs paths (docs, docs/foo.md, docs/sub/dir/foo.md, ./docs/foo.md) -> True. - repo-relative meta paths (AGENTS.md, README.md, .github/copilot-instructions.md, docs_other/foo.md) -> False. - absolute paths inside docs/ -> True; inside repo root but outside docs/ -> False. - traversal attempts (../other/foo.md, docs/../AGENTS.md) -> False. CI behavior unchanged: tj-actions/changed-files passes repo-relative paths, which were already handled by the previous logic. --- scripts/doc-linter.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'scripts/doc-linter.py') diff --git a/scripts/doc-linter.py b/scripts/doc-linter.py index c86ff29a..f580fcdc 100644 --- a/scripts/doc-linter.py +++ b/scripts/doc-linter.py @@ -32,12 +32,23 @@ SUPPORTED_EXTS = ('.md', '.rst', '.txt') # Linter only applies to published documentation sources under docs/. Repo-root # files (README.md, AGENTS.md, .github/copilot-instructions.md) are project # meta, not docs content, and are out of scope. -DOCS_ROOT = 'docs' + os.sep +DOCS_ROOT = 'docs' def is_docs_path(path): - norm = os.path.normpath(path) - return norm == 'docs' or norm.startswith(DOCS_ROOT) + """Return True iff `path` resolves under the repo's `docs/` tree. + + Accepts both repo-relative and absolute paths. Paths are normalized + against the linter's working directory (CI invokes it from the repo + root; the same is expected for local runs). + """ + abs_path = os.path.abspath(path) + abs_docs = os.path.abspath(DOCS_ROOT) + try: + return os.path.commonpath([abs_path, abs_docs]) == abs_docs + except ValueError: + # commonpath raises on mixed drives (Windows) or empty input. + return False # MyST / Markdown fenced code block: leading whitespace + 3+ backticks or 3+ colons. # Same character and length-or-greater closes. -- cgit v1.2.3