summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2026-05-22conntrack: T8308: Enhancements to the `show conntrack table` op-mode commandOleksandr Kuchmystyi
- Display per-flow packet and byte counters (original and reply direction). - Add VRF filter option `show conntrack table <ipv4|ipv6> vrf <vrf-name>`.
2026-05-20Merge pull request #2053 from natali-rs1985/T7059Viacheslav Hletenko
high-availability: T7059: Add persistence-timeout option in virtual-server
2026-05-20high-availability: T7059: Add persistence-timeout option in virtual-serverNataliia Solomko
2026-05-18Merge pull request #2052 from ↡Viacheslav Hletenko
teslazonda/update-target-branch-in-write-documentation-tutorial Update upstream Git branch to 'rolling' in 'Write Documentation' instructions
2026-05-18Update Git branch to 'rolling'Quill Cronwall
Update the upstream Git branch from 'current' to 'rolling in the 'Write Documentation' instructions.
2026-05-15Merge pull request #2048 from vyos/mergify/configuration-deprecated-updateViacheslav Hletenko
ci(mergify): upgrade configuration to current format
2026-05-15ci(mergify): upgrade configuration to current formatmergify[bot]
2026-05-14bgp: T8607: Add CLI support for BGP update-delay and establish-wait (#1891)Nataliia S.
* bgp: T8607: Add CLI support for BGP update-delay and establish-wait * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * T8607: Apply Copilot's suggestions --------- Co-authored-by: Christian Breunig <christian@breunig.cc> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-14Merge pull request #2043 from ↡Yuriy Andamasov
vyos/yuriy/ai-validation-skip-prepare-on-bot-author ci(ai-validation): skip prepare on Mergify-authored PRs
2026-05-14ci(ai-validation): skip prepare on Mergify-authored PRsYuriy Andamasov
Lifts the existing Mergify-author short-circuit (today inside validate's `secrets-check` step) to a job-level `if:` on `prepare`, so the whole pipeline skips for backport/queue PRs. Why now: every Mergify backport whose merge ref shares no shallow ancestor with the (advanced) base branch fails the prepare step at git diff "$BASE...HEAD" --name-only ... fatal: FETCH_HEAD...HEAD: no merge base (because base is `git fetch --no-tags --depth=1` and the merge ref is `fetch-depth: 2`). Proximate symptom: run 25842928620 on PR #2042 (sagitta backport of #2023). AI Validation isn't a required check so the queue isn't blocked, but every Mergify backport is left with a red "prepare" check that adds noise to PR review. The validate-level skip in commit 0e8a2956 was correct for the "claude-code-action rejects bot-initiated runs" failure mode but fires too late β€” prepare has already run and crashed before validate's `if: needs.prepare.outputs.has_md_changes == 'true'` even evaluates. Implementation: single job-level `if:` on prepare. validate's `needs: [prepare]` cascades the skip naturally (skipped needs make the dependent's expression-based `if:` evaluate against empty outputs). The in-step author check in validate stays as defense-in-depth. πŸ€– Generated by [robots](https://vyos.io)
2026-05-14Merge pull request #2023 from vyos/yuriy/doc-linter-cleanup-followupsYuriy Andamasov
ci(doc-linter): fix 12 accumulated bugs flagged across PR #2014/#2019/#2020 reviews
2026-05-14ci(doc-linter): anchor .. code-block:: detection + drop debug printYuriy Andamasov
Addresses Copilot review on PR #2023: 1. .. code-block:: tracking was triggered by a plain substring check, which matched mid-line occurrences too. In MD prose like ``.. code-block::`` (docs/documentation.md:222) this set in_rst_codeblock=True spuriously and could suppress line-length checks downstream. Replace with a leading-whitespace- anchored regex and gate on file_ext in ('.rst', '.txt') or an open {eval-rst} MyST fence so the directive opener is only recognized where it can actually occur. 2. print('start') in main() was leftover debug noise β€” remove it.
2026-05-14Merge pull request #2024 from vyos/yuriy/cli-aws-doc-fixesYuriy Andamasov
docs: fix CLI typo, orphan fences, CloudWatch case, terraformvyos link labels
2026-05-14docs(cli, aws): hard-wrap pre-existing long prose lines to <=80 charsYuriy Andamasov
doc-lint regression on [vyos-documentation#2024](https://github.com/vyos/vyos-documentation/pull/2024): the CI workflow's `scripts/doc-linter.py` scans every line of every changed file (not just changed lines), so the typo fix on `cli.md:464` and the capitalization fix on `aws.md:118` surfaced 57 pre-existing >80-char violations that have lived on rolling since the MyST migration. `cli.md` β€” 53 prose paragraphs hard-wrapped at word boundaries to 80 chars, preserving content fidelity. List items use hanging-indent continuations under their `- ` marker. No content reworded; only soft-wrap β†’ hard-wrap. `aws.md` β€” wrapped the inline AWS GWLB blog link (L164) and the References section (L185-187) with `% stop_vyoslinter` / `% start_vyoslinter` markers. These are URL-bearing lines that cannot be shortened (URL itself >80 chars). Verified locally: `python3 scripts/doc-linter.py "['docs/cli.md','docs/installation/cloud/aws.md','docs/automation/terraform/terraformvyos.md']"` β†’ exit 0, no violations. πŸ€– Generated by [robots](https://vyos.io)
2026-05-14docs(terraform): wrap long install URL in vyoslinter suppressionYuriy Andamasov
The full HashiCorp install-CLI URL is 79 chars, so any reference definition `[X]: <URL>` form exceeds the 80-char docs-lint limit regardless of label length. Existing `% stop_vyoslinter` / `% start_vyoslinter` markers in this file were back-to-back with no content between them (flagged by Copilot on [vyos-documentation#2021](https://github.com/vyos/vyos-documentation/pull/2021)) β€” put them to work by wrapping the long `[install Terraform]:` reference. The shorter `[Terraform introduction]:` reference (73 chars) sits outside the suppression range. Both Copilot and CodeRabbit flagged the docs-lint regression on [vyos-documentation#2024](https://github.com/vyos/vyos-documentation/pull/2024) β€” verified locally with `python3 scripts/doc-linter.py docs/automation/terraform/terraformvyos.md`: no warnings. πŸ€– Generated by [robots](https://vyos.io)
2026-05-14Merge pull request #2027 from vyos/yuriy/ai-validation-skip-mergifyYuriy Andamasov
ci(ai-validation): skip validation on Mergify-authored PRs
2026-05-14ci(ai-validation): skip validation on Mergify-authored PRsYuriy Andamasov
The upstream anthropics/claude-code-action rejects bot-initiated workflow runs with: Workflow initiated by non-human actor: mergify (type: Bot). Add bot to allowed_bots list or use '*' to allow all bots. This leaves a failing required check on every Mergify backport PR (#2025 today is the proximate symptom β€” circinus backport of #2016 is blocked from auto-merging by this). Per org policy, Mergify-authored PRs skip the bot-review flow entirely: the underlying change was already reviewed on the source PR. Re-running validation on the backport would also post duplicate findings. Fix: extend the existing `secrets-check` step (kept the id for backwards compat with the cascade of `if: steps.secrets-check.outputs.skip != 'true'` gates) to also short-circuit when `github.event.pull_request.user.login` equals `mergify[bot]`. Add a `skip_reason` output so the notify-on-PR step can distinguish bot-skip (silent) from missing-secrets (post a notice comment). Implementation notes: - PR author is bound through env: PR_AUTHOR (same pattern as secret bindings) so the template-expansion happens before bash sees the value as an already-quoted env variable. - Uses `printf '...%s\n' "$PR_AUTHOR"` for the notice line so the shell β€” not the YAML template engine β€” interpolates the author into the workflow log output. - Renamed step name to "Decide whether to skip validation" to reflect the broader scope; step id stays `secrets-check`. πŸ€– Generated by [robots](https://vyos.io)
2026-05-14docs(terraform): replace non-descriptive [link]/[install] reference labelsYuriy Andamasov
Surfaced by CodeRabbit on the circinus RSTβ†’MD conversion PR [vyos-documentation#2021](https://github.com/vyos/vyos-documentation/pull/2021) (`terraformvyos.md:14`). Both labels violate MD059 (descriptive link text) β€” generic words like "link" don't convey the destination to screen-reader users or search indexers. Pre-existing on rolling; out of scope for the conversion port, fixed here at the source. Mergify will backport to circinus and sagitta. Sibling `automation/terraform/index.md` already uses the descriptive form ([Terraform], [Ansible]). πŸ€– Generated by [robots](https://vyos.io)
2026-05-14Merge pull request #2016 from vyos/yuriy/fix-need-improvement-mystYuriy Andamasov
fix(includes): rewrite need_improvement.txt as MyST so plain `{include}` renders correctly
2026-05-14fix(includes): wrap admonition in `{only} not latex` to preserve PDF suppressionYuriy Andamasov
The original RST `_include/need_improvement.txt` wrapped the admonition in `.. raw:: latex \iffalse / \fi`, intentionally hiding the "Call for Contributions" notice from the LaTeX/PDF builder (see b222a313, 2020). `.readthedocs.yml` enables `formats: - pdf` and `conf.py` configures `latex_elements`/`latex_documents`, so PDF output is a real downstream artifact. The previous commit (82a06e1d) dropped that suppression. Restore it using Sphinx's `only` directive with `not latex`, which is the MyST equivalent of the original RST builder-conditional pattern. Spotted by Copilot inline review on #2016. πŸ€– Generated by [robots](https://vyos.io)
2026-05-13ci(doc-linter): fix \b regression in compressed-IPv6 regex β€” replace bare ↡copilot-swe-agent[bot]
removal with word-boundary prefix Agent-Logs-Url: https://github.com/vyos/vyos-documentation/sessions/cdefcaf2-e89e-4090-b39a-15b385b774df Co-authored-by: andamasov <12631358+andamasov@users.noreply.github.com>
2026-05-14docs: fix CLI typo, orphan colon fences, CloudWatch capitalizationYuriy Andamasov
Three pre-existing rolling docs bugs, surfaced by Copilot review on the sagitta RSTβ†’MD conversion PR #2022 against the byte-for-byte ports of `cli.md` and `aws.md`: - `cli.md` line 464: `set interface ethernet …` is wrong; the CLI command is `set interfaces ethernet …` (plural). Users copying the example verbatim would hit "Configuration path is not valid". - `cli.md` lines 527-528: orphan `:::` / `::::` fence closers after the `{cfgcmd} save` block. The `(save)=` directive opens at line 503 and closes at line 506; the two `` ``` none `` blocks at 508-526 are self-contained; nothing opens these colon fences. MyST/Sphinx tolerates them silently today but they're literal noise. Drop both. - `aws.md` line 118: "Cloudwatch" β†’ "CloudWatch", matching the surrounding correctly-cased uses on lines 115/121/122 and AWS's product naming. Mergify will backport to circinus and sagitta via the standard `@Mergifyio backport circinus sagitta` post-merge. πŸ€– Generated by [robots](https://vyos.io)
2026-05-14ci(lint-doc): pin all GitHub Actions to commit SHAsYuriy Andamasov
Each `uses:` line was pinned to a mutable version tag (`@v6`, `@v0.8.4`, …). Tags can be rewritten to point to malicious code β€” CVE-2025-30066 (reviewdog/action-setup) and the tj-actions/changed-files incident in 2025 are the canonical real-world examples. GitHub's hardening guide for Actions recommends pinning to full-length commit SHAs and keeping the tag as a trailing comment for human readability. Resolved each action's tag to its commit SHA via `gh api /repos/<repo>/git/refs/tags/<tag>` and verified the SHA is a commit (not an annotated-tag object) via `gh api /repos/<repo>/git/commits/<sha>`: - actions/checkout v6 -> de0fac2e4500dabe0009e67214ff5f5447ce83dd - bullfrogsec/bullfrog v0.8.4 -> 1831f79cce8ad602eef14d2163873f27081ebfb3 - trilom/file-changes-action v1.2.4 -> a6ca26c14274c33b15e6499323aac178af06ad4b - actions/setup-python v6 -> a309ff8b426b58ec0e2a45f0f869d46889d02405 This change covers `lint-doc.yml` only. A fleet-wide sweep across every workflow in `.github/workflows/` is a separate effort β€” worth doing because the drift / supply-chain risk is the same in every one. Tracked as a follow-up to this PR's review. Tracked as item 11 of the rolling-side cleanup backlog from PR #2014 / #2019 / #2020 reviews. πŸ€– Generated by [robots](https://vyos.io)
2026-05-14ci(doc-linter): lint added + renamed files, not only modifiedYuriy Andamasov
Previous workflow: env: FILES_MODIFIED: ${{ steps.file_changes.outputs.files_modified }} run: python scripts/doc-linter.py "$FILES_MODIFIED" `trilom/file-changes-action`'s `files_modified` output is modifications-only. A PR adding a new `.md`/`.rst` doc page passed `files_added`, never `files_modified`, so a brand-new page with long lines or real public IPs slipped past the linter entirely. Workflow: also pass `files_added` and `files_renamed` as separate positional args. Each output is a JSON array (action v1.2.4) and is passed via env to avoid shell-quoting issues. Linter: `main()` now accepts one OR multiple positional argv entries, each a JSON array of paths. Arrays are merged and deduplicated before linting. Single-arg invocations remain backward-compatible. Switched from `ast.literal_eval` to `json.loads` β€” the action's outputs are JSON, and `json.loads` is the right tool (and dodges literal_eval-via-`eval`-substring linter warnings). Test coverage: - Two JSON arrays merge -> single linter run on union. - Empty-string argv entry skipped (no `files_renamed` in many PRs). - Malformed JSON -> falls back to walking DOCS_ROOT. - No argv -> walks DOCS_ROOT. - Single-arg invocation -> backward-compat preserved. Tracked as item 7 of the rolling-side cleanup backlog from PR #2014 / #2019 / #2020 reviews. πŸ€– Generated by [robots](https://vyos.io)
2026-05-14ci(doc-linter): exclude docs/_rst_legacy/ and docs/_build/ from lint scopeYuriy Andamasov
`is_docs_path()` returned True for any path under `docs/`, including the archived RST shadows under `docs/_rst_legacy/` and the build output under `docs/_build/`. Sphinx excludes both from the build (per `docs/conf.py`'s exclude_patterns) and AGENTS marks `_rst_legacy` as reference-only. The linter shouldn't process either. Add a `DOCS_EXCLUDED_SUBDIRS = ('_build', '_rst_legacy')` constant. After confirming a path is under `docs/`, walk each excluded subtree and reject the path if it's contained. Also unify the auto-discover walk fallback to call `is_docs_path()` for the filter β€” previously it had its own hand-rolled `"_build" not in path` check that didn't handle `_rst_legacy` at all and would have walked the entire legacy archive. Prune `dirs[:]` in-place at each walk level so we don't descend into the excluded subtrees in the first place β€” optimization on top of correctness. Reverted the `_dirs` -> `dirs` rename here because we now mutate it. Test coverage: 10 hand-coded `is_docs_path()` cases β€” all pass: - `docs/configuration/foo.md` -> True - `docs/_rst_legacy/foo.rst` -> False (was True) - `docs/_rst_legacy/subdir/rst-foo.rst` -> False (was True) - `docs/_build/html/index.html` -> False (was True) - `docs/_include/foo.txt` -> True (live snippets stay in scope) - `docs` -> True - `AGENTS.md`, `README.md`, `.github/copilot-instructions.md`, `scripts/doc-linter.py` -> False (already correct) Tracked as item 4 of the rolling-side cleanup backlog from PR #2014 / #2019 / #2020 reviews. πŸ€– Generated by [robots](https://vyos.io)
2026-05-14ci(doc-linter): distinguish prose-bearing directive fences from code blocksYuriy Andamasov
The line-length skip was test_line_length = not (in_md_fence or in_rst_codeblock) `in_md_fence` was True for every MyST/Markdown fence regardless of content type. That includes admonition directives like `:::{note}`, `:::{warning}`, `:::{tip}` whose content is normal prose, not preformatted code. Long lines in admonitions were silently skipped, contradicting the documented 80-char rule which exempts code blocks only. Track an `is_code` property on each fence-stack entry. A fence is code-bearing when: - info string is empty (plain ``` per CommonMark), OR - info string doesn't start with `{` (bare language tag like `python`, `bash`, `yaml`), OR - info string is `{<directive>}` and `<directive>` is in the CODE_BEARING_DIRECTIVES set (`code-block`, `code`, `sourcecode`, `cfgcmd`, `opcmd`, `cmdinclude`, `cmdincludemd`, `literalinclude`, `parsed-literal`, `raw`, `command-output`, `eval-rst`). Anything else is prose-bearing (`{note}`, `{warning}`, `{tip}`, `{deprecated}`, `{seealso}`, …) and its content gets line-length checked. `in_md_code_fence` checks the topmost stack entry β€” the innermost fence wins, so a `{note}` containing an inner `{code-block}` lints the outer prose lines and skips the inner code-block body. The classic `is_suppression_marker()` call still uses `in_md_fence` because suppression markers are about "any fence depth" not "code-bearing depth". `{eval-rst}` is kept in CODE_BEARING_DIRECTIVES to preserve current behavior β€” its body is RST and any line-length on nested `.. code-block::` is handled by the separate RST tracker. Tightening eval-rst is a separate change if wanted. Test coverage: - `_fence_is_code` classifier: 16 cases (code-like vs prose-like) all pass. - Integration: long line in `{note}` flagged βœ“; long line in ```python``` not flagged βœ“; long line in `{cfgcmd}` not flagged βœ“; nested `{note}` > ```text``` β€” inner skipped βœ“; nested `{note}` > prose β€” flagged βœ“. Sweep over current `docs/` tree: 28 new warnings surface across the existing pages (long prose inside admonition directives that the previous logic had been silently hiding). CI on PR scope is changed files only, so the new findings appear only when contributors touch those pages β€” they won't break this PR or future infra PRs. Tracked as item 5 of the rolling-side cleanup backlog from PR #2014 / #2019 / #2020 reviews. πŸ€– Generated by [robots](https://vyos.io)
2026-05-14ci(doc-linter): fix RST code-block exit on short dedented linesYuriy Andamasov
The dedent check inside `handle_file_action()` was if in_rst_codeblock: if len(line) > rst_codeblock_indent and not line[rst_codeblock_indent].isspace(): in_rst_codeblock = False This worked only when the next line was at least `rst_codeblock_indent + 1` chars long β€” the indexing `line[rst_codeblock_indent]` requires that. A short dedented line (e.g., a single character at column 0 under a directive indented at column 4) failed the length guard and `in_rst_codeblock` stayed True. The block remained open longer than it should, suppressing line-length checks on subsequent prose until either EOF or the next `.. code-block::` reset the state. Replace with a leading-whitespace-count check: on any non-blank line, exit the block when leading-ws is <= the directive's column. Blank lines don't reset the block context. Test: a 3-line file with `.. code-block:: text` directive at col 0, one body line, a single `a` at col 0, then a 113-char line at col 0. With the old logic the long line is still treated as inside the code block and not flagged. With the new logic the single-`a` dedent exits the block and the long line is flagged as expected. Tracked as items 6 and 12 of the rolling-side cleanup backlog from PR #2014 / #2019 / #2020 reviews. πŸ€– Generated by [robots](https://vyos.io)
2026-05-14ci(doc-linter): drop \s prefix from compressed-IPv6 regex branchYuriy Andamasov
The leading-compression group in `IPV6GROUPS` was r'(?:\s' + IPV6SEG + r':){1,7}:' The `\s` required whitespace before each hextet in the repeated group. In practice this meant compressed forms with leading hextets β€” `2001:db8::`, `64:ff9b::`, `fe80::1` β€” only matched when preceded by whitespace inside the line. The linter calls `lint_ipv6(line.strip())`, so at start-of-stripped-line there's no whitespace, and the address fell through to no match. Real-world impact: a documentation page mentioning `2001:4860:4860::8888` (Google DNS) or `64:ff9b::1` (NAT64 well-known prefix) at the start of a line silently passed the IPv6 documentation-address check. None of the other groups in `IPV6GROUPS` use a `\s` prefix. This one was inconsistent. Drop the `\s` so the branch matches compressed forms directly, like its peers. Verified with 6 hand-coded cases (RFC 3849 doc range, Google DNS, NAT64 prefix, mid-line and start-of-line positions). All pass. Tracked as item 3 of the rolling-side cleanup backlog from PR #2014 / #2019 / #2020 reviews. πŸ€– Generated by [robots](https://vyos.io)
2026-05-14ci(doc-linter): check every IP on a line, not just the firstYuriy Andamasov
`lint_ipv4()` and `lint_ipv6()` used `re.search`, which returns only the first match. A line like Set DNS forwarder 192.0.2.1 then fall back to 8.8.8.8 flagged nothing because `192.0.2.1` (RFC 5737 documentation range) is allowed and the search stopped there. The real public IP `8.8.8.8` slipped through despite being exactly the case the linter was meant to catch. Switch both functions to `re.finditer` and walk every match: return on the first disallowed address; only return None when all matches on the line are allowed (private / multicast / non-global). Also fix the casing of "private space" in both error messages β€” was "private Space" with a stray capital. Verified with 7 hand-coded cases (allowed + public mixes, boundary cases, IPv6 RFC 3849 / Google DNS). All pass. Tracked as items 1, 2, and 10 of the rolling-side cleanup backlog from PR #2014 / #2019 / #2020 reviews. πŸ€– Generated by [robots](https://vyos.io)
2026-05-14ci(doc-linter): delete lint_AS placeholderYuriy Andamasov
`lint_AS()` and its `NUMBER` regex were a placeholder for a future AS-number documentation-range check (RFC 5398). `lint_AS()` was never called from anywhere β€” it'd merely `pass` on `re.search` hit. Pure dead code that made it look like AS-number linting existed when it didn't. Delete: - the `NUMBER` regex constant - the `lint_AS()` function If/when AS-number linting is actually desired, implement it properly: hook into the lint loop in `handle_file_action()`, return the standard `(message, line, severity)` tuple on violations, and define the allowed AS ranges from `/^AGENTS.md/` (currently 64496–64511 and 65536–65551). Tracked as item 8 of the rolling-side cleanup backlog from PR #2014 / #2019 / #2020 reviews. πŸ€– Generated by [robots](https://vyos.io)
2026-05-14ci(doc-linter): delete lint_mac dead codeYuriy Andamasov
`lint_mac()` was called and its return value immediately overwritten with `None`: err_mac = lint_mac(cnt, line.strip()) # disable mac detection for the moment, too many false positives err_mac = None The comment is correct β€” MAC linting produced too many false positives β€” but the cleanup never landed. The dead call ran on every line for every linted file, and the function/MAC-regex/MAC-error-text all sat in the source as a misleading hint that MAC linting was a live feature. Delete: - the `MAC` regex constant - the `lint_mac()` function - the `err_mac = lint_mac(...)`, `err_mac = None`, and the `err_mac` entry in the tuple iterated by the error-collection loop in `handle_file_action()` Tracked as item 9 of the rolling-side cleanup backlog flagged across the PR #2014 / #2019 / #2020 reviews. When MAC linting is genuinely wanted again, recover the regex/function from git history and wire it in cleanly. πŸ€– Generated by [robots](https://vyos.io)
2026-05-13Merge pull request #2014 from vyos/claude/update-readme-myst-wCUzgYuriy Andamasov
docs(readme): reflect completed MyST migration
2026-05-13doc-linter: narrow argv parsing exception scope to (IndexError, SyntaxError, ↡Claude
ValueError) CodeRabbit / Ruff BLE001: the previous 'except Exception as e:' on the explicit-file-list path caught any error, masking runtime failures from handle_file_action() as silent fallback behavior. Only input validation errors from ast.literal_eval(sys.argv[1]) should trigger the fallback walk. Refactor: - Wrap only the parse step in try/except, catching just IndexError (missing argv[1]), SyntaxError (malformed literal), and ValueError (non-literal input). - On parse failure, set files = None and dispatch to the DOCS_ROOT walk via an explicit 'else' branch. - On parse success, run the file loop outside the try so any errors from handle_file_action() propagate normally and CI fails loudly. Also drops the unused 'as e' (Ruff BLE001 noise) and the implicit catch of TypeError (e.g. ast.literal_eval('42') returns an int and 'for file in 42:' would have been silently swallowed -> fallback walk; now it raises clearly). Verified scenarios: - explicit file list (CI normal path) -> exit 0. - no argv -> IndexError caught -> walks DOCS_ROOT. - malformed argv ('not-a-list') -> SyntaxError caught -> walks DOCS_ROOT. - explicit list with a non-existent file -> FileNotFoundError propagates (previously silently triggered a fallback walk). - explicit list with a non-list literal ('42') -> TypeError propagates (programming error stays visible).
2026-05-13doc-linter: rename unused walker var to _dirsClaude
CodeRabbit nit (Ruff B007): the dirs variable from os.walk(DOCS_ROOT) in the auto-discover fallback is unused. Renaming to _dirs makes the intent explicit and silences the warning.
2026-05-13doc-linter: realpath() resolution, DOCS_ROOT in walker, indent fixClaude
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.
2026-05-13docs(linter): add one-line docstrings to clear coverage warningYuriy Andamasov
CodeRabbit Pre-merge Docstring Coverage check reported 50% on scripts/doc-linter.py (threshold 80%). Add minimal one-line docstrings to each public function; no behavior change. πŸ€– Generated by [robots](https://vyos.io)
2026-05-13Merge pull request #2015 from vyos/yuriy/mergify-fix-tid-override-rule-nameYuriy Andamasov
ci(mergify): fix T-ID-override rule name to match central baseline
2026-05-13fix(includes): rewrite need_improvement.txt as MyST so plain `{include}` ↡Yuriy Andamasov
renders correctly After the RSTβ†’MyST migration, ~45 MD pages use the plain `{include}` MyST directive to pull in `_include/need_improvement.txt`. The included file still contained RST (`.. raw:: html`, `.. raw:: latex`, `:ref:`), and MyST's built-in `{include}` parses the content with the *outer* file's parser β€” i.e. as MyST. RST directives then render as literal paragraphs. Visible symptom on docs.vyos.io/en/rolling (and across 1.5/1.4): the VPP index, VPP subpages, haproxy, isis, bfd, policy, pki, salt, flowtables, webproxy, and others all show: .. raw:: latex \iffalse .. raw:: html Call for Contributions Help improve this section ... For contribution guidelines, see :ref: documentation . Fix: rewrite `_include/need_improvement.txt` as a native MyST admonition (`:::{admonition} Call for Contributions / :class: error / ... / :::`) and drop the now-unnecessary `{eval-rst}` wrapper at the single callsite (`configuration/highavailability/index.md`) that wrapped the include for RST processing. The fix is companion to 9c815d68 (cmdincludemd RST plumbing) but targets the plain-`{include}` path which doesn't route through our custom extension. πŸ€– Generated by [robots](https://vyos.io)
2026-05-13ci(mergify): fix T-ID-override rule name to match central baselineYuriy Andamasov
The override shipped in 3d44fe06 used rule names `Flag PR title not matching T-ID format` + `Flag commit message not matching T-ID format`. Per Mergify `extends:` semantics, same-name rules in the child REPLACE the parent's β€” and the central baseline in vyos/mergify uses a single rule named `Flag T-ID format violation in PR title or commit messages`. Different names β†’ no replacement β†’ parent rule keeps firing. Symptom (surfaced on PR #2014, title `docs(readme): …`): every PR without a `T<digits>:` token gets `invalid-title` labeled. Fix: collapse to one rule, rename to match the parent exactly. The condition (`closed AND -closed`) still never matches, so `toggle` removes the label on every evaluation β€” picks up any stale `invalid-title` from the broken-override window. The parent rule does not toggle `invalid-commit-title`; the second child rule for that label was extraneous and is dropped. πŸ€– Generated by [robots](https://vyos.io)
2026-05-13doc-linter: handle absolute paths in is_docs_path()Claude
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.
2026-05-13docs(agents): doc-linter is in-repo, scoped to docs/ β€” fix stale referencesClaude
Two stale claims flagged by Copilot in PR #2014 (one comment marked the other as 'same issue earlier in the file'): - '## Lint' (L40-45): said 'vyoslinter (doc-linter.py from the vyos/.github repo, via the lint-doc.yml workflow) on changed files only'. The cross-repo dependency was dropped in 1bf386e β€” the linter is now scripts/doc-linter.py in this repo, invoked from .github/workflows/lint-doc.yml. - '## CI' (L290-292): same stale claim in bullet form. Also reflect 65a8e9f's scoping decision: the linter applies only to files under docs/. Repo-root meta files (README.md, AGENTS.md, .github/copilot-instructions.md) are explicitly out of scope, since they are project meta rather than published documentation and don't need to obey docs-publication conventions (80-char wrap, RFC IP rules, suppression markers). Mention that exclusion in the CI bullet so contributors know the linter won't catch issues there.
2026-05-13ci(doc-linter): scope to docs/ only β€” skip repo-root meta filesYuriy Andamasov
The linter targets published documentation sources; the auto-discover fallback already walks `docs/` only. CI was passing root-level meta files (README.md, AGENTS.md, .github/copilot-instructions.md β€” the last is a symlink to AGENTS.md) which forced docs-publication conventions (80-char wrap, RFC IP rules, suppression markers) onto project meta that has no business obeying them. Add an `is_docs_path()` guard in `main()` so the explicit-file-list path matches the auto-discover behavior β€” only files under `docs/` are linted. AGENTS.md and the Copilot-instruction symlink are now out of scope. Verified: - `python3 scripts/doc-linter.py "['AGENTS.md', 'README.md', '.github/copilot-instructions.md']"` β†’ exit 0 (all skipped). - `python3 scripts/doc-linter.py "['docs/_test_lint.md']"` with a real public IP β†’ still errors as expected. πŸ€– Generated by [robots](https://vyos.io)
2026-05-13docs(agents): address Copilot review on stale RST-era conventionsClaude
Four follow-up findings from Copilot on commit e8d7e43, all valid: - '### Formatting' bullet 'Inline code: use double backticks per RST convention' was carried over from the RST era. The .md sources are overwhelmingly single-backtick (~1900 single- vs ~80 double-backtick inline-code spans across docs/). Rewrite to 'single backticks in MyST (the canonical form). Double backticks only inside {eval-rst} blocks and _include/*.txt snippets, per RST convention.' - '### RST heading hierarchy' section read like a general authoring rule. Add a preface scoping it explicitly to RST contexts (_include/*.txt and {eval-rst} blocks) and noting that canonical MyST pages use ATX (# / ## / ...) headings. Reword the post-block prose to 'every embedded RST snippet that introduces a title' instead of 'every RST file'. - '### `.. TODO::` markers' heading and prose described the RST form only. The .md sources use `{todo}` fenced directives exclusively (6 triple-backtick + 1 colon-fenced occurrences across docs/, zero `.. TODO::` in .md). Rename the section to '`{todo}` markers', describe the MyST fenced form first, and mention the RST form only for RST contexts. - Drop the '% stop_vyoslinter' / '% start_vyoslinter' markers I added around the '8.8.8.8' DNS example bullet under '### IP addresses'. Replace the literal IP with a description-only example ('a DNS server's address in a DNS forwarder example, or an upstream peer's address in an EBGP example'). The bullet still illustrates the rule (real public IPs need suppression) without rendering bare '% stop_vyoslinter' lines in GitHub views. Local doc-linter still exits 0 on AGENTS.md and README.md.
2026-05-13docs(agents): reflect completed MyST migration + bulk hard-wrap to 80 charsClaude
The previous README refresh sweep landed before the doc-linter was extended to MyST in 7a3aa29, so AGENTS.md was never wrapped to the 80-char rule its own 'Source conventions' section documents, and the source-format claims drifted out of sync once the RST->MyST migration finished. Content fixes (the inconsistency Copilot flagged on PR #2014): - '## Project': drop the 'MyST Markdown for migrated pages and RST for pages that haven't been migrated yet' framing. State plainly that sources are MyST Markdown only, source_suffix is ['.md'], and the RST archive under docs/_rst_legacy/ is not editable. - '### Sphinx config': source_suffix entry updated from ['.rst', '.md'] to ['.md']. - '### Source files': drop the 'docs/<page>.rst' non-migrated bullet (no such pages exist). Add a 'docs/_include/<name>.txt' bullet noting that the shared snippets stay RST because cmdincludemd parses their content as RST. - '**Editing rules:**': collapse 'Migrated page' / 'Non-migrated page' into one 'Existing page' rule. Add a bullet pointing at the _include/*.txt -> RST exception. - '### Command directives': rewrite to lead with MyST fenced blocks (the canonical form) and only mention RST forms for {eval-rst} blocks and _include/*.txt snippets. Avoid using literal quad-backtick code-in-code samples that would otherwise open phantom fences in the source. Linter compliance: - Hard-wrap every paragraph and bullet outside fenced code blocks to <=80 chars (~30 pre-existing violations). - Wrap the long line about the docutils inline-markup link by dropping the link entirely; the rule 'use double backticks' is self-contained and AGENTS.md doesn't need the reference. - Restructure '### Bot review workflow' table: shorten the CodeRabbit row to 79 chars and move the 'auto-reviews are disabled' note to a paragraph below the table. - Wrap the '8.8.8.8' real-public-IP bullet under '### IP addresses' with '% stop_vyoslinter' / '% start_vyoslinter' markers. The surrounding section is literally documenting suppression markers, so the meta-example reads naturally. - The '### Configuration page structure' bullet referring to MD fence syntax was using quad-backtick code-in-code; rewritten to '`{cfgcmd}` fenced code blocks (in MD)' to avoid opening a phantom fence in the linter's view of the source.
2026-05-13docs(readme): wrap pre-existing long lines for MyST doc-lintClaude
The doc-linter was extended to MyST .md files in 7a3aa29 (after the previous README refresh in 3a544f6), so this PR is the first README edit linted under MyST rules. The three pre-existing >80-char lines (badge, Wayback link, rolling table row) now fail doc-lint. Wrap them: - Switch the badge and Wayback links to reference-style. The badge destination/image URLs become [badge]/[rtd]/[wayback] references at the top of the file; renders identically on GitHub and in Sphinx. - Trim the Wayback snapshot path from web/20200225171529/ to web/2020/ (year-level capture, same era as the original snapshot) to fit the reference definition in 80 chars without a suppression marker. Using % stop_vyoslinter here would render literally on GitHub, since the README is GFM-rendered, not MyST. - Shorten the rolling-branch table row from 'all new contributions target this' to 'new contributions land here' (84 -> 78 chars). Also address two Copilot review findings on this PR: - Line 15 grammar: 'Pages are ... and build with Sphinx' -> 'Pages are ... and are built with Sphinx'. - AGENTS.md still describes the source format as mixed MyST/RST (AGENTS.md:7 and several follow-up sections). Updating AGENTS.md in this PR would pull ~30 pre-existing long-line violations into scope and require a bulk hard-wrap of the file, which is outside the original README request. Leaving AGENTS.md for a follow-up PR and noting it in the PR description.
2026-05-13docs(readme): reflect completed MyST migrationClaude
The MyST migration is complete: source_suffix in docs/conf.py is now ['.md'] only, all canonical pages are .md, and the pre-migration RST originals are archived under docs/_rst_legacy/ (excluded from the build). Update the README accordingly: - Add a 'Source format' section stating pages are MyST Markdown and pointing at the _rst_legacy/ archive so newcomers know not to edit it. Mention that the VyOS command directives are written as MyST fenced blocks via myst_fence_as_directive, and that docs/_include/ *.txt snippets stay RST because cmdincludemd parses their content as RST (per 9c815d6). - Drop the stale 'MyST Markdown for migrated pages, RST for the rest' line from the Contributing section; rephrase to point at the actual topics AGENTS.md covers today (MyST conventions, command directives, linter suppression markers, Copilot/CodeRabbit workflow).
2026-05-13pseudo-ethernet: T8540: Add anycast-gateway support for EVPNOleksandr Kuchmystyi
Introduce 'anycast-gateway' option for pseudo-ethernet interfaces. When set, a local FDB entry is installed on the parent bridge to prevent the shared anycast MAC from leaking over the VXLAN overlay.
2026-05-12Merge pull request #1997 from vyos/claude/scan-typos-errors-VJZ5EViacheslav Hletenko
docs: fix typos across configuration, contributing, and vpp docs
2026-05-12Merge pull request #2008 from vyos/claude/bold-ptolemy-dd70feYuriy Andamasov
fix(ext): cmdincludemd parses .txt content as RST to fix broken interface docs
2026-05-12Merge pull request #2009 from vyos/yuriy/mergify-disable-title-tid-checkYuriy Andamasov
ci(mergify): disable inherited T-ID title/commit-message checks in this repo