diff options
| author | Claude <noreply@anthropic.com> | 2026-05-13 20:35:38 +0000 |
|---|---|---|
| committer | Claude <noreply@anthropic.com> | 2026-05-13 20:35:51 +0000 |
| commit | 5d1c2d74d1e18e80b788e5778b10b94053343c2c (patch) | |
| tree | e84482e09a8aa40c5b83f292c21ba4f2ec96d5e0 | |
| parent | bad55da626f59fd84e85e8f6d9a826ae1f0b8860 (diff) | |
| download | vyos-documentation-5d1c2d74d1e18e80b788e5778b10b94053343c2c.tar.gz vyos-documentation-5d1c2d74d1e18e80b788e5778b10b94053343c2c.zip | |
doc-linter: realpath() resolution, DOCS_ROOT in walker, indent fix
Three Copilot findings on ab497bf:
1. is_docs_path() docstring claimed paths 'resolve' under docs/, but
the implementation only normalized via abspath() — a symlink under
docs/ that points outside the tree would be treated as in-scope.
Switch both inputs to os.path.realpath() so symlinks are followed
to their real targets. The reverse case is also handled: if docs/
is itself a symlink (some CI checkouts), realpath() resolves it
consistently for both sides of the commonpath comparison.
Verified with a synthetic case: docs/poison.md -> /etc/hosts now
returns False (with abspath() it returned True).
2. The auto-discover fallback in main() still hardcoded
os.walk('docs') instead of using the new DOCS_ROOT constant.
Use DOCS_ROOT in both paths so the docs root is configured in
exactly one place.
3. Indentation inside 'for file in files:' was double-indented (8
spaces under the for, instead of 4) — pre-existing oddity from
before 65a8e9f, preserved through the is_docs_path() addition.
Normalize to a single indent level under the loop.
CI behavior unchanged: tj-actions/changed-files passes repo-relative
paths with no symlinks under docs/, which were already handled. The
realpath() switch only changes behavior in the symlink-escape case,
which was a bug.
| -rw-r--r-- | scripts/doc-linter.py | 31 |
1 files changed, 18 insertions, 13 deletions
diff --git a/scripts/doc-linter.py b/scripts/doc-linter.py index 9f1e6f57..c3304718 100644 --- a/scripts/doc-linter.py +++ b/scripts/doc-linter.py @@ -38,12 +38,17 @@ DOCS_ROOT = 'docs' def is_docs_path(path): """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). + Accepts both repo-relative and absolute paths. Both `path` and + `DOCS_ROOT` are resolved with `os.path.realpath`, so symlinks are + followed to their real targets — a symlink under `docs/` that + points outside the tree is correctly treated as out-of-scope, and + a `docs/` that is itself a symlink (e.g., in some CI checkouts) is + correctly treated as the docs root. 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) + abs_path = os.path.realpath(path) + abs_docs = os.path.realpath(DOCS_ROOT) try: return os.path.commonpath([abs_path, abs_docs]) == abs_docs except ValueError: @@ -248,15 +253,15 @@ def main(): try: files = ast.literal_eval(sys.argv[1]) for file in files: - if ( - file.endswith(SUPPORTED_EXTS) - and "_build" not in file - and is_docs_path(file) - ): - if handle_file_action(file) is False: - bool_error = False + if ( + file.endswith(SUPPORTED_EXTS) + and "_build" not in file + and is_docs_path(file) + ): + if handle_file_action(file) is False: + bool_error = False except Exception as e: - for root, dirs, files in os.walk("docs"): + for root, dirs, files in os.walk(DOCS_ROOT): path = root.split(os.sep) for file in files: if file.endswith(SUPPORTED_EXTS) and "_build" not in path: |
