Skip to content

Bump rpds-py from 0.24.0 to 0.26.0#375

Merged
danischm merged 1 commit intomainfrom
dependabot/pip/rpds-py-0.26.0
Aug 5, 2025
Merged

Bump rpds-py from 0.24.0 to 0.26.0#375
danischm merged 1 commit intomainfrom
dependabot/pip/rpds-py-0.26.0

Conversation

@dependabot
Copy link
Copy Markdown
Contributor

@dependabot dependabot bot commented on behalf of github Jul 1, 2025

Bumps rpds-py from 0.24.0 to 0.26.0.

Release notes

Sourced from rpds-py's releases.

v0.26.0

What's Changed

Full Changelog: crate-py/rpds@v0.25.1...v0.26.0

v0.25.1

What's Changed

New Contributors

Full Changelog: crate-py/rpds@v0.25.0...v0.25.1

v0.25.0

What's Changed

New Contributors

Full Changelog: crate-py/rpds@v0.24.0...v0.25.0

Commits
  • ff9278f Tag a release.
  • d2f69ef Update requirements.
  • 58ee607 Merge pull request #146 from edgarrmondragon/136-require-maturin-1.9-pep639
  • 5433ab6 Require maturin>=1.9.0 to ensure support for PEP 639
  • 7557e53 Merge pull request #144 from crate-py/dependabot/github_actions/github/codeql...
  • d0963ae Merge pull request #145 from crate-py/dependabot/github_actions/astral-sh/set...
  • 513ec22 Bump astral-sh/setup-uv from 6.3.0 to 6.3.1
  • cbb4277 Bump github/codeql-action from 3.29.0 to 3.29.2
  • 25123e9 Merge pull request #143 from crate-py/dependabot/github_actions/PyO3/maturin-...
  • 7a59bb7 Merge pull request #142 from crate-py/dependabot/github_actions/astral-sh/set...
  • Additional commits viewable in compare view

Dependabot compatibility score

You can trigger a rebase of this PR by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot merge will merge this PR after your CI passes on it
  • @dependabot squash and merge will squash and merge this PR after your CI passes on it
  • @dependabot cancel merge will cancel a previously requested merge and block automerging
  • @dependabot reopen will reopen this PR if it is closed
  • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Note
Automatic rebases have been disabled on this pull request as it has been open for over 30 days.

Bumps [rpds-py](https://github.com/crate-py/rpds) from 0.24.0 to 0.26.0.
- [Release notes](https://github.com/crate-py/rpds/releases)
- [Commits](crate-py/rpds@v0.24.0...v0.26.0)

---
updated-dependencies:
- dependency-name: rpds-py
  dependency-version: 0.26.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot bot added dependencies Pull requests that update a dependency file python Pull requests that update Python code labels Jul 1, 2025
@danischm danischm merged commit 7e445a3 into main Aug 5, 2025
6 checks passed
@danischm danischm deleted the dependabot/pip/rpds-py-0.26.0 branch August 5, 2025 17:52
aitestino added a commit that referenced this pull request Jan 20, 2026
* Bump pluggy from 1.5.0 to 1.6.0 (#365)

Bumps [pluggy](https://github.com/pytest-dev/pluggy) from 1.5.0 to 1.6.0.
- [Changelog](https://github.com/pytest-dev/pluggy/blob/main/CHANGELOG.rst)
- [Commits](pytest-dev/pluggy@1.5.0...1.6.0)

---
updated-dependencies:
- dependency-name: pluggy
  dependency-version: 1.6.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump click from 8.2.0 to 8.2.1 (#368)

Bumps [click](https://github.com/pallets/click) from 8.2.0 to 8.2.1.
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.rst)
- [Commits](pallets/click@8.2.0...8.2.1)

---
updated-dependencies:
- dependency-name: click
  dependency-version: 8.2.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump typer from 0.15.3 to 0.16.0 (#371)

Bumps [typer](https://github.com/fastapi/typer) from 0.15.3 to 0.16.0.
- [Release notes](https://github.com/fastapi/typer/releases)
- [Changelog](https://github.com/fastapi/typer/blob/master/docs/release-notes.md)
- [Commits](fastapi/typer@0.15.3...0.16.0)

---
updated-dependencies:
- dependency-name: typer
  dependency-version: 0.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump requests from 2.32.3 to 2.32.4 (#372)

Bumps [requests](https://github.com/psf/requests) from 2.32.3 to 2.32.4.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](psf/requests@v2.32.3...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump urllib3 from 2.4.0 to 2.5.0 (#374)

Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](urllib3/urllib3@2.4.0...2.5.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.5.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump rpds-py from 0.24.0 to 0.26.0 (#375)

Bumps [rpds-py](https://github.com/crate-py/rpds) from 0.24.0 to 0.26.0.
- [Release notes](https://github.com/crate-py/rpds/releases)
- [Commits](crate-py/rpds@v0.24.0...v0.26.0)

---
updated-dependencies:
- dependency-name: rpds-py
  dependency-version: 0.26.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump cryptography from 44.0.3 to 45.0.5 (#376)

Bumps [cryptography](https://github.com/pyca/cryptography) from 44.0.3 to 45.0.5.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](pyca/cryptography@44.0.3...45.0.5)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 45.0.5
  dependency-type: indirect
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Migrate to uv

* Refactor error handling

* Various linter updates

* Dependency updates

* Update readme

* Update dependencies and pyproject

* Fix dependency

* Fix robot dependency

* Update versions

* Bump astral-sh/setup-uv from 6 to 7 (#388)

Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6 to 7.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](astral-sh/setup-uv@v6...v7)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* License header updates

* Update changelog

* Update dependabot config for uv

* Bump nac-yaml version

* 1.1.0 version bump

* Bump actions/upload-artifact from 4 to 5 (#391)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix lint workflow for fork prs

* Expose pabot's process option to nac-test cli (#393)

* Increase robot loglevel to debug when verbosity=DEBUG is used (#394)

* Add robotframework-jmespath dependency (#395)

* Update README to include jmespath and add test for 3rd party libs (#396)

* Add support for test case parallelization for capable suites (#390)

* Switch from pabot.main to pabot.main_program and handle exit codes (#400)

Change nac-test to use pabot's main_program() instead of main() to avoid
sys.exit() calls and properly handle exit codes. This allows nac-test to
control the exit behavior and return appropriate exit codes to the caller.

Key changes:
- Update run_pabot() to call pabot.pabot.main_program() instead of main()
- Change run_pabot() return type from None to int
- Return exit code from pabot execution
- Update CLI main() to capture and use exit code
- Remove try/except wrapper in CLI main() - let exceptions propagate
- Disable typer pretty exceptions for cleaner error output

Benefits:
- Proper exit code handling (test failures, errors, etc.)
- No unexpected sys.exit() calls
- Cleaner error messages without verbose typer tracebacks
- Better integration with CI/CD systems

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for passing Robot Framework options to nac-test (#399)

* Add support for passing Robot Framework options to nac-test

Users can now pass additional Robot Framework options directly to
nac-test, which are validated and appended to the pabot invocation.
This enables advanced use cases like custom variables, listeners,
and logging configuration without modifying nac-test's core options.

Key changes:
- Enable extra args in CLI via typer context settings
- Add parse_and_validate_extra_args() to validate Robot Framework options
- Reject pabot-specific options (--processes, --testlevelsplit, etc.)
- Reject datasources/test files in extra arguments
- Return exit code 252 for invalid extra arguments
- Separate pabot_args and robot_args for proper argument ordering
- Add comprehensive unit tests (14 tests covering all scenarios)
- Add type hints and fix all mypy errors
- Update CLI help text to document extra args feature

Implementation details:
- Uses pabot's parse_args() to validate options against Robot Framework
- Filters out datasources and pabot-specific options
- Appends validated args to robot_args before pabot invocation
- Proper error handling with logging and exit codes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Remove pabot.main_program changes from robot-args branch

This commit removes the pabot-specific changes (main_program, exit codes,
exception handling) that belong in the separate pabot-call branch. The
robot-args branch now focuses solely on the extra arguments feature.

Changes:
- Revert run_pabot() return type from int to None
- Use pabot.pabot.main() instead of main_program()
- Remove exit code handling (no return 252)
- Keep try/except in CLI main() for proper error handling
- Update tests to use pabot.pabot.main mock
- Update tests to expect exceptions instead of error codes

The extra args validation and appending logic remains unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Revert "Remove pabot.main_program changes from robot-args branch"

This reverts commit df21b98.

---------

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for chunking templates (#398)

* Update changelog and readms

* Update lock file

* Expand test coverage for chunk split test (#401)

* Fix typo in readme link

* Remove library version numbers from readme

* 1.2.0 version bump

* Support rendering on windows (#404)

* Bump actions/checkout from 5 to 6 (#402)

Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update changelog

* 1.2.1 version bump

* Bump actions/upload-artifact from 5 to 6 (#418)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: resolve all ruff linting errors and warnings

Fix code quality issues identified by ruff to ensure compliance with
project style guidelines and best practices.

Changes:
- Fix syntax error in pabot.py (space in != operator)
- Add missing filecmp import in test_integration.py
- Add proper exception chaining (from e) for B904 violations
- Rename unused loop variables to prefix with underscore (B007)
- Remove trailing whitespace from blank lines (W293)
- Modernize Union type annotations to use | operator (UP007)
- Remove unused Union import after migration to | syntax
- Exclude test fixture directories from ruff checks in pyproject.toml

All ruff checks now pass successfully.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix pabot module import in tests/unit/test_pabot_args.py

* no longer test for RESTinstance robot lib

* add fixture to set bogus ACI_xxx environment for nac-test to pass rendering tests

* add/fix --processes feature

* fix/add ordering_file logic to robot orchestrator

* fix/add passing extra cli args to robot orchestrator

* add integration test for extra args

* update README.md

* fix ruff config changes broken during merge conflict resolution

* fix: resolve all mypy type checking errors

This commit addresses 11 mypy type errors across 4 files:

- connection_utils.py: Add type annotations for dict parameters and
  update function signature to accept None values that are validated
- subprocess_runner.py: Remove unreachable code branch in output
  processing that was flagged due to redundant None check
- connection_broker.py: Add type annotations for testbed attribute,
  AsyncIterator return type, and assertion for loader result
- robot_writer.py: Remove duplicate method definition and add explicit
  type annotation to prevent incorrect type narrowing

All files now pass mypy strict type checking without errors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: restore custom_data handling in render_template for chunked templates

The refactoring that moved data conversion to initialization (for
performance) inadvertently broke the chunked template functionality
by not using the custom_data parameter when provided.

The render_template method now correctly checks if custom_data is
provided (used for chunked templates) and converts it on-demand,
otherwise uses the pre-converted self.template_data.

This fixes the test_nac_test_list_chunked test which was failing
after merging main into the feature branch.

Fixes functionality added in commits 18da546 and ced5983.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* ruff formatting fixes

* fix: add type stub dependencies to pre-commit mypy hook

The pre-commit mypy hook runs in an isolated environment and needs
type stubs explicitly specified via additional_dependencies. Without
these, mypy complains about missing type information for yaml, aiofiles,
and markdown modules.

Added:
- types-PyYAML>=6.0.12.20250822
- types-aiofiles>=24.1.0.20250822
- types-markdown>=3.8.0.20250809

This aligns the pre-commit environment with the project dependencies
and allows mypy to properly type-check imports from these libraries.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: add type annotations to unit test functions

Add proper type annotations to all test functions in tests/unit to
resolve mypy strict type checking errors. Changes include:

- Add -> None return type annotations to all test methods
- Add type annotations for mock parameters (mock_logger,
  mock_connection_class, etc.) using typing.Any
- Add explicit type annotation for connections list variable
- Add type: ignore comment for intentional type mismatch in test

This ensures tests pass mypy strict type checking while maintaining
test clarity and avoiding over-specification of mock types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller tests from shell environment variables

Add autouse fixture to clear all controller-related environment
variables (ACI_*, SDWAN_*, CC_*, MERAKI_*, FMC_*, ISE_*) before
each test in TestCombinedOrchestratorController.

This ensures tests run in a clean environment and results are not
influenced by the caller's shell environment, preventing false
failures when developer has controller credentials set in their
shell.

The fixture uses pytest's monkeypatch to safely remove environment
variables only for the duration of each test.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor: migrate integration test fixture to use monkeypatch

Replace manual environment variable setup/teardown with pytest's
monkeypatch fixture for safer and more robust test isolation.

Benefits of monkeypatch approach:
- Automatic cleanup guaranteed even if test fails
- Safe deletion with raising=False (no KeyError if var missing)
- Preserves and restores original environment variable values
- Less boilerplate code (no yield/try-finally needed)
- Thread-safe state management handled by pytest

The fixture now uses monkeypatch.setenv() which automatically saves
the original value (if any) and restores it after the test, ensuring
the caller's shell environment is never permanently modified.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller detection integration tests from shell environment

Add autouse fixture to clear all controller-related environment
variables before each test in TestControllerDetectionIntegration.

This prevents test failures when developers have controller credentials
set in their shell environment. Without this fix, tests would fail with
"Multiple controller credentials detected" errors when shell variables
conflicted with test-specific environment setup.

The fixture uses pytest's monkeypatch.delenv() with raising=False for
safe deletion that won't fail if a variable doesn't exist.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* add license headers

* add missing test fixture template for extra args test

* security: replace hardcoded /tmp with tempfile.gettempdir() in ConnectionBroker

Fix Bandit B108 vulnerability by using tempfile.gettempdir() instead of
hardcoded /tmp path for output_dir default value. This ensures
cross-platform compatibility and respects system-specific temporary
directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: add usedforsecurity=False to MD5 hash in AuthCache

Fix Bandit B324 vulnerability by explicitly marking MD5 usage as not for
security purposes. The hash is only used to generate cache filenames from
URLs, not for cryptographic security.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp references in emergency dump

Fix Bandit B108 vulnerabilities by:
- Using tempfile.gettempdir() instead of hardcoded /tmp path
- Dynamically checking if file is in temp directory instead of string matching "/tmp/"
- Updated docstrings and log messages to reflect system temp dir usage

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in AUTH_CACHE_DIR constant

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for AUTH_CACHE_DIR.
This ensures cross-platform compatibility and respects system-specific
temporary directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in batching reporter overflow dir

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for default
overflow directory. This ensures cross-platform compatibility while
still allowing override via NAC_TEST_OVERFLOW_DIR environment variable.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: enable Jinja2 autoescape to prevent XSS vulnerabilities

Fix Bandit B701 vulnerability by enabling autoescape for HTML, XML, and
.j2 files using select_autoescape(). This prevents potential XSS attacks
when rendering user-controlled data in HTML reports.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* gitignore bandit-security-report.json created during pipeline run

* Update readme cli help output

* rename robot/pabot integration test file

* Add netconf related packages and update dependencies

* 1.2.2 version bump

* refactor: centralize DEBUG_MODE constant for progressive disclosure

Consolidates the NAC_TEST_DEBUG environment variable check into a single
constant in core/constants.py, eliminating repeated inline checks.

Changes:
- Add DEBUG_MODE constant to nac_test/core/constants.py
- Update cli/main.py to use DEBUG_MODE for pretty_exceptions_enable
- Update combined_orchestrator.py to use DEBUG_MODE for exception handling
- Update batching_reporter.py to use DEBUG_MODE (2 locations)

This enables progressive disclosure: customers get clean error output by
default, while developers can set NAC_TEST_DEBUG=true for full exception
context and verbose tracebacks when debugging.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: danischm <danischm@cisco.com>
Co-authored-by: Oliver Boehmer <oli@spine.de>
Co-authored-by: Oliver Boehmer <oboehmer@cisco.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Justyna Chowaniec <79261946+juchowan@users.noreply.github.com>
aitestino added a commit that referenced this pull request Jan 21, 2026
* Bump pluggy from 1.5.0 to 1.6.0 (#365)

Bumps [pluggy](https://github.com/pytest-dev/pluggy) from 1.5.0 to 1.6.0.
- [Changelog](https://github.com/pytest-dev/pluggy/blob/main/CHANGELOG.rst)
- [Commits](pytest-dev/pluggy@1.5.0...1.6.0)

---
updated-dependencies:
- dependency-name: pluggy
  dependency-version: 1.6.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump click from 8.2.0 to 8.2.1 (#368)

Bumps [click](https://github.com/pallets/click) from 8.2.0 to 8.2.1.
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.rst)
- [Commits](pallets/click@8.2.0...8.2.1)

---
updated-dependencies:
- dependency-name: click
  dependency-version: 8.2.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump typer from 0.15.3 to 0.16.0 (#371)

Bumps [typer](https://github.com/fastapi/typer) from 0.15.3 to 0.16.0.
- [Release notes](https://github.com/fastapi/typer/releases)
- [Changelog](https://github.com/fastapi/typer/blob/master/docs/release-notes.md)
- [Commits](fastapi/typer@0.15.3...0.16.0)

---
updated-dependencies:
- dependency-name: typer
  dependency-version: 0.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump requests from 2.32.3 to 2.32.4 (#372)

Bumps [requests](https://github.com/psf/requests) from 2.32.3 to 2.32.4.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](psf/requests@v2.32.3...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump urllib3 from 2.4.0 to 2.5.0 (#374)

Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](urllib3/urllib3@2.4.0...2.5.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.5.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump rpds-py from 0.24.0 to 0.26.0 (#375)

Bumps [rpds-py](https://github.com/crate-py/rpds) from 0.24.0 to 0.26.0.
- [Release notes](https://github.com/crate-py/rpds/releases)
- [Commits](crate-py/rpds@v0.24.0...v0.26.0)

---
updated-dependencies:
- dependency-name: rpds-py
  dependency-version: 0.26.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump cryptography from 44.0.3 to 45.0.5 (#376)

Bumps [cryptography](https://github.com/pyca/cryptography) from 44.0.3 to 45.0.5.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](pyca/cryptography@44.0.3...45.0.5)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 45.0.5
  dependency-type: indirect
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Migrate to uv

* Refactor error handling

* Various linter updates

* Dependency updates

* Update readme

* Update dependencies and pyproject

* Fix dependency

* Fix robot dependency

* Update versions

* Bump astral-sh/setup-uv from 6 to 7 (#388)

Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6 to 7.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](astral-sh/setup-uv@v6...v7)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* License header updates

* Update changelog

* Update dependabot config for uv

* Bump nac-yaml version

* 1.1.0 version bump

* Bump actions/upload-artifact from 4 to 5 (#391)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix lint workflow for fork prs

* Expose pabot's process option to nac-test cli (#393)

* Increase robot loglevel to debug when verbosity=DEBUG is used (#394)

* Add robotframework-jmespath dependency (#395)

* Update README to include jmespath and add test for 3rd party libs (#396)

* Add support for test case parallelization for capable suites (#390)

* Switch from pabot.main to pabot.main_program and handle exit codes (#400)

Change nac-test to use pabot's main_program() instead of main() to avoid
sys.exit() calls and properly handle exit codes. This allows nac-test to
control the exit behavior and return appropriate exit codes to the caller.

Key changes:
- Update run_pabot() to call pabot.pabot.main_program() instead of main()
- Change run_pabot() return type from None to int
- Return exit code from pabot execution
- Update CLI main() to capture and use exit code
- Remove try/except wrapper in CLI main() - let exceptions propagate
- Disable typer pretty exceptions for cleaner error output

Benefits:
- Proper exit code handling (test failures, errors, etc.)
- No unexpected sys.exit() calls
- Cleaner error messages without verbose typer tracebacks
- Better integration with CI/CD systems

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for passing Robot Framework options to nac-test (#399)

* Add support for passing Robot Framework options to nac-test

Users can now pass additional Robot Framework options directly to
nac-test, which are validated and appended to the pabot invocation.
This enables advanced use cases like custom variables, listeners,
and logging configuration without modifying nac-test's core options.

Key changes:
- Enable extra args in CLI via typer context settings
- Add parse_and_validate_extra_args() to validate Robot Framework options
- Reject pabot-specific options (--processes, --testlevelsplit, etc.)
- Reject datasources/test files in extra arguments
- Return exit code 252 for invalid extra arguments
- Separate pabot_args and robot_args for proper argument ordering
- Add comprehensive unit tests (14 tests covering all scenarios)
- Add type hints and fix all mypy errors
- Update CLI help text to document extra args feature

Implementation details:
- Uses pabot's parse_args() to validate options against Robot Framework
- Filters out datasources and pabot-specific options
- Appends validated args to robot_args before pabot invocation
- Proper error handling with logging and exit codes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Remove pabot.main_program changes from robot-args branch

This commit removes the pabot-specific changes (main_program, exit codes,
exception handling) that belong in the separate pabot-call branch. The
robot-args branch now focuses solely on the extra arguments feature.

Changes:
- Revert run_pabot() return type from int to None
- Use pabot.pabot.main() instead of main_program()
- Remove exit code handling (no return 252)
- Keep try/except in CLI main() for proper error handling
- Update tests to use pabot.pabot.main mock
- Update tests to expect exceptions instead of error codes

The extra args validation and appending logic remains unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Revert "Remove pabot.main_program changes from robot-args branch"

This reverts commit df21b98.

---------

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for chunking templates (#398)

* Update changelog and readms

* Update lock file

* Expand test coverage for chunk split test (#401)

* Fix typo in readme link

* Remove library version numbers from readme

* 1.2.0 version bump

* feat(path_setup): auto-discover pyats_common for test imports

Add find_pyats_common_parent() to search test directory tree for
pyats_common subdirectory and add its parent to PYTHONPATH. This
enables test files to use simple imports like:
  from pyats_common.apic_base_test import APICTestBase

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* add verbose option to pyats when running at DEBUG level, log pyats output as well when in DEBUG

* current state, not yet working

* add simple test for pipeline - WIP

* add integration tests and support for mock devices

* use easypy.run to invoke script

* do not assume a default CONTROLLER_TYPE

* remove assumption for CONTROLLER_TYPE being ACI in base_test too

* adjust test

* add some debug log statements

* add warning about potential issues with python3.11 on macOS

* connect using log_stdout=False

* fix simple test, and ruff formatting

* simple test changes, WIP

* Support rendering on windows (#404)

* Bump actions/checkout from 5 to 6 (#402)

Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update changelog

* 1.2.1 version bump

* update with mock flask server - WIP

* remove debug logs

* add mock-server to perform API testing in integration tests

* add integration tests for quicksilver-generated templates

* add type hints

* Bump actions/upload-artifact from 5 to 6 (#418)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* add sdwan mock api results

* adjust mock-server file, create mock-server test

* fix: resolve all ruff linting errors and warnings

Fix code quality issues identified by ruff to ensure compliance with
project style guidelines and best practices.

Changes:
- Fix syntax error in pabot.py (space in != operator)
- Add missing filecmp import in test_integration.py
- Add proper exception chaining (from e) for B904 violations
- Rename unused loop variables to prefix with underscore (B007)
- Remove trailing whitespace from blank lines (W293)
- Modernize Union type annotations to use | operator (UP007)
- Remove unused Union import after migration to | syntax
- Exclude test fixture directories from ruff checks in pyproject.toml

All ruff checks now pass successfully.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix pabot module import in tests/unit/test_pabot_args.py

* no longer test for RESTinstance robot lib

* add fixture to set bogus ACI_xxx environment for nac-test to pass rendering tests

* add/fix --processes feature

* fix/add ordering_file logic to robot orchestrator

* fix/add passing extra cli args to robot orchestrator

* add integration test for extra args

* update README.md

* fix ruff config changes broken during merge conflict resolution

* fix: resolve all mypy type checking errors

This commit addresses 11 mypy type errors across 4 files:

- connection_utils.py: Add type annotations for dict parameters and
  update function signature to accept None values that are validated
- subprocess_runner.py: Remove unreachable code branch in output
  processing that was flagged due to redundant None check
- connection_broker.py: Add type annotations for testbed attribute,
  AsyncIterator return type, and assertion for loader result
- robot_writer.py: Remove duplicate method definition and add explicit
  type annotation to prevent incorrect type narrowing

All files now pass mypy strict type checking without errors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: restore custom_data handling in render_template for chunked templates

The refactoring that moved data conversion to initialization (for
performance) inadvertently broke the chunked template functionality
by not using the custom_data parameter when provided.

The render_template method now correctly checks if custom_data is
provided (used for chunked templates) and converts it on-demand,
otherwise uses the pre-converted self.template_data.

This fixes the test_nac_test_list_chunked test which was failing
after merging main into the feature branch.

Fixes functionality added in commits 18da546 and ced5983.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* ruff formatting fixes

* fix: add type stub dependencies to pre-commit mypy hook

The pre-commit mypy hook runs in an isolated environment and needs
type stubs explicitly specified via additional_dependencies. Without
these, mypy complains about missing type information for yaml, aiofiles,
and markdown modules.

Added:
- types-PyYAML>=6.0.12.20250822
- types-aiofiles>=24.1.0.20250822
- types-markdown>=3.8.0.20250809

This aligns the pre-commit environment with the project dependencies
and allows mypy to properly type-check imports from these libraries.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: add type annotations to unit test functions

Add proper type annotations to all test functions in tests/unit to
resolve mypy strict type checking errors. Changes include:

- Add -> None return type annotations to all test methods
- Add type annotations for mock parameters (mock_logger,
  mock_connection_class, etc.) using typing.Any
- Add explicit type annotation for connections list variable
- Add type: ignore comment for intentional type mismatch in test

This ensures tests pass mypy strict type checking while maintaining
test clarity and avoiding over-specification of mock types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller tests from shell environment variables

Add autouse fixture to clear all controller-related environment
variables (ACI_*, SDWAN_*, CC_*, MERAKI_*, FMC_*, ISE_*) before
each test in TestCombinedOrchestratorController.

This ensures tests run in a clean environment and results are not
influenced by the caller's shell environment, preventing false
failures when developer has controller credentials set in their
shell.

The fixture uses pytest's monkeypatch to safely remove environment
variables only for the duration of each test.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor: migrate integration test fixture to use monkeypatch

Replace manual environment variable setup/teardown with pytest's
monkeypatch fixture for safer and more robust test isolation.

Benefits of monkeypatch approach:
- Automatic cleanup guaranteed even if test fails
- Safe deletion with raising=False (no KeyError if var missing)
- Preserves and restores original environment variable values
- Less boilerplate code (no yield/try-finally needed)
- Thread-safe state management handled by pytest

The fixture now uses monkeypatch.setenv() which automatically saves
the original value (if any) and restores it after the test, ensuring
the caller's shell environment is never permanently modified.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller detection integration tests from shell environment

Add autouse fixture to clear all controller-related environment
variables before each test in TestControllerDetectionIntegration.

This prevents test failures when developers have controller credentials
set in their shell environment. Without this fix, tests would fail with
"Multiple controller credentials detected" errors when shell variables
conflicted with test-specific environment setup.

The fixture uses pytest's monkeypatch.delenv() with raising=False for
safe deletion that won't fail if a variable doesn't exist.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* add license headers

* add missing test fixture template for extra args test

* security: replace hardcoded /tmp with tempfile.gettempdir() in ConnectionBroker

Fix Bandit B108 vulnerability by using tempfile.gettempdir() instead of
hardcoded /tmp path for output_dir default value. This ensures
cross-platform compatibility and respects system-specific temporary
directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: add usedforsecurity=False to MD5 hash in AuthCache

Fix Bandit B324 vulnerability by explicitly marking MD5 usage as not for
security purposes. The hash is only used to generate cache filenames from
URLs, not for cryptographic security.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp references in emergency dump

Fix Bandit B108 vulnerabilities by:
- Using tempfile.gettempdir() instead of hardcoded /tmp path
- Dynamically checking if file is in temp directory instead of string matching "/tmp/"
- Updated docstrings and log messages to reflect system temp dir usage

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in AUTH_CACHE_DIR constant

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for AUTH_CACHE_DIR.
This ensures cross-platform compatibility and respects system-specific
temporary directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in batching reporter overflow dir

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for default
overflow directory. This ensures cross-platform compatibility while
still allowing override via NAC_TEST_OVERFLOW_DIR environment variable.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: enable Jinja2 autoescape to prevent XSS vulnerabilities

Fix Bandit B701 vulnerability by enabling autoescape for HTML, XML, and
.j2 files using select_autoescape(). This prevents potential XSS attacks
when rendering user-controlled data in HTML reports.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* gitignore bandit-security-report.json created during pipeline run

* Update readme cli help output

* rename robot/pabot integration test file

* Add netconf related packages and update dependencies

* 1.2.2 version bump

* adjust and fix aci integration tests

* remove environment vars after testing

* fix license check

* remove unfinished tests

* use tmpdir

* add debugging for CI troubleshooting

* attempt to fix event loop issue in CI

* add more debug code to troubleshoot CI failure

* add missing nac-test-pyats-common  to CI pipeline

* sum up passed/failed for check (in case we have multiple results.json files)

* re-organize test case fixture directories

use a common base dir, and then add specific archs as subdirectories to avoid directory bloat in fixture directory

* Fix Python 3.12 asyncio compatibility with get_or_create_event_loop

Python 3.12 changed asyncio.get_event_loop() behavior to raise
RuntimeError when called from the main thread without an active event loop,
breaking async operations that run synchronous PyATS/Unicon calls via
loop.run_in_executor().

Previous behavior (Python 3.10-3.11):
- asyncio.get_event_loop() automatically created a new event loop if none existed

New behavior (Python 3.12+):
- asyncio.get_event_loop() raises RuntimeError if no event loop exists
- Must explicitly call asyncio.new_event_loop() and set_event_loop()

Solution:
Created get_or_create_event_loop() helper that handles both behaviors:
- Tries to get existing event loop
- If closed or RuntimeError, creates and sets a new loop
- Works across Python 3.10-3.12+

Replaced 9 instances of asyncio.get_event_loop() across 4 modules:
- nac_test/pyats_core/broker/connection_broker.py (3 calls)
- nac_test/pyats_core/common/ssh_base_test.py (3 calls)
- nac_test/pyats_core/ssh/connection_manager.py (2 calls)
- nac_test/pyats_core/reporting/multi_archive_generator.py (1 call)

These calls are used to run blocking Unicon operations (connect, disconnect,
execute) in thread pools via run_in_executor() to prevent blocking the
async event loop.

* add sdwan integration tests (both api and d2d)

* add license header

* test: remove test_mock_server.py - tests mock infrastructure, not business logic

These tests only verify that the MockAPIServer returns what it was
configured to return:
- test_mock_api_server_endpoint_matching: configures endpoints, asserts they return configured data
- test_nac_test_with_mock_api_complex_urls: same pattern with complex URLs
- test_nac_test_with_mock_api_dynamic: adds endpoint with response X, asserts response is X

This violates the principle: "What MUST NEVER be Tested: whether mocks
return what you told them to return."

The mock server is infrastructure to enable testing real business logic,
not something that needs its own test coverage.

* test: remove test_controller_detection_consistency - tests Python determinism

This test calls detect_controller_type() three times with identical
environment and asserts all results are equal. This tests whether Python
functions return consistent results when called with the same inputs -
which is testing Python's deterministic execution, not business logic.

A pure function will always return the same result for the same inputs.
Testing this adds no value unless there's caching or stateful behavior
that could cause inconsistency (there isn't).

Violates: "What MUST NEVER be Tested: Whether Python's standard library works"

* test: remove mock assertion from test_end_to_end_controller_detection

Removed the pattern that mocks EnvironmentValidator and asserts it was
called with the correct argument:

    with patch("...EnvironmentValidator") as mock_validator:
        orchestrator.validate_environment()
        mock_validator.validate_controller_env.assert_called_once_with("SDWAN")

This tests whether validate_environment() calls EnvironmentValidator with
the right argument - essentially testing "whether one-line wrapper functions
call the functions they wrap."

The real test is already done: assert orchestrator.controller_type == "SDWAN"
which validates the business logic (controller was correctly detected).

Violates: "What MUST NEVER be Tested: whether one-line wrapper functions
call the functions they wrap"

* fix(tests): remove conflicting copyright header and fix resource leak

mock_unicon.py changes:
- Removed Cisco proprietary copyright header (lines 5-7), keeping only MPL-2.0
- Fixed resource leak: file opened without context manager now uses 'with' statement

Before:
  states = yaml.safe_load(open(os.path.join(mock_data_dir, file))) or []

After:
  with open(os.path.join(mock_data_dir, file)) as f:
      states = yaml.safe_load(f) or []

* fix(tests): implement proper server startup and shutdown for MockAPIServer

mock_server.py changes:
- Replaced time.sleep(0.5) race condition with proper readiness polling
- Added _wait_for_server_ready() that polls until server responds or timeout
- Implemented proper stop() method using werkzeug.serving.make_server
- Added reset_endpoints() method to clear dynamic endpoints while preserving
  YAML-loaded baseline (enables test isolation with session-scoped fixture)
- Added SERVER_STARTUP_TIMEOUT_SECONDS and SERVER_POLL_INTERVAL_SECONDS constants

This fixes flaky test failures caused by server not being ready, and
prevents port conflicts from improper shutdown.

* fix(tests): add endpoint reset and isolated fixture for test isolation

conftest.py changes:
- Updated mock_api_server fixture to call reset_endpoints() after yield
- Added mock_api_server_isolated fixture (function-scoped) for tests that
  add dynamic endpoints, preventing cross-test pollution

The session-scoped mock_api_server now resets to baseline state between
tests, while mock_api_server_isolated provides per-test isolation.

* fix(tests): use absolute path and fix PEP8 naming in test_pyats_standard

test_pyats_standard.py changes:
- Fixed hardcoded relative path that breaks when run from different directories
  Now uses Path(__file__).parent to construct absolute path to mock_unicon.py
- Renamed classes tc_one -> TcOne, tc_two -> TcTwo (PEP8 CamelCase)
- Fixed decorator spacing: '@ aetest.test' -> '@aetest.test'

* fix(tests): replace debug prints with logging and use monkeypatch

test_integration_pyats.py changes:
- Replaced all print() debug statements with logger.debug() calls
- Moved 'import json' from inside function to module level
- Refactored environment variable handling to use monkeypatch.setenv()
  instead of manual os.environ manipulation with try/finally
- Removed commented-out debug code for static output directories

This improves test maintainability and ensures proper cleanup via
pytest's monkeypatch fixture.

* fix(tests): modernize type hints and use monkeypatch in robot_pabot tests

test_integration_robot_pabot.py changes:
- Changed all tmpdir: str parameters to tmp_path: Path (modern pytest fixture)
- Refactored environment variable handling to use monkeypatch.setenv()
  instead of manual os.environ with try/finally cleanup
- Updated fixture references from tmpdir to tmp_path throughout
- Used Path methods (.exists(), .touch()) instead of os.path equivalents

This improves type safety and ensures proper test isolation via pytest's
automatic cleanup of monkeypatched environment variables.

* fix(tests): replace obfuscated code and emojis in PyATS quicksilver tests

templates_pyats_qs test changes (3 files):
- verify_sdwanmanager_all_sd_wan_edge_configurations_are_in_sync.py
- verify_iosxe_all_sd_wan_control_connections_are_up.py
- verify_aci_apic_appliance_operational_status.py

Changes applied to all:
- Replaced chr(10) with '\n' for clarity
- Replaced emoji markers with text: ❌ -> [FAIL], ✅ -> [PASS]

This prevents encoding issues in CI logs and improves code readability.

* fix(tests): extract f-string join to variable for Python 3.11 compatibility

Python 3.11 does not allow backslash escapes inside f-string expressions.
The previous commit replaced chr(10) with '\n' but left it inside the
f-string expression, causing a SyntaxError.

This fix extracts the join operation to a separate variable before using
it in the f-string:

    failures_text = '\n'.join(failures)
    f"{failures_text}\n\n"

* fix(tests): add proxy bypass for localhost in integration tests

Add session-scoped autouse fixture to ensure 127.0.0.1 is included in
the no_proxy/NO_PROXY environment variables. This prevents the mock API
server requests from being routed through corporate proxies, which was
causing 504 Gateway Timeout errors in environments with proxy configured.

The fixture preserves original proxy settings and restores them after
the test session completes.

* refactor(tests): split robot_pabot tests into focused modules

Split the 493-line test_integration_robot_pabot.py into 4 focused
test modules following Single Responsibility Principle:

- test_cli_basic.py: Basic CLI execution tests (6 tests)
- test_cli_rendering.py: Template rendering tests (8 tests)
- test_cli_ordering.py: Robot test ordering tests (4 tests)
- test_cli_extra_args.py: Extra arguments tests (5 tests)

Improvements:
- Added Google-style docstrings to all 23 test functions
- Renamed generic test names to descriptive names
- Added assertion messages to all assert statements
- Extracted magic number to named constant (ROBOT_ARGUMENT_ERROR_EXIT_CODE)

* add management_ip_variable to test fixture data

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: danischm <danischm@cisco.com>
Co-authored-by: Oliver Boehmer <oli@spine.de>
Co-authored-by: Oliver Boehmer <oboehmer@cisco.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Justyna Chowaniec <79261946+juchowan@users.noreply.github.com>
oboehmer added a commit that referenced this pull request Mar 19, 2026
* Bump pluggy from 1.5.0 to 1.6.0 (#365)

Bumps [pluggy](https://github.com/pytest-dev/pluggy) from 1.5.0 to 1.6.0.
- [Changelog](https://github.com/pytest-dev/pluggy/blob/main/CHANGELOG.rst)
- [Commits](pytest-dev/pluggy@1.5.0...1.6.0)

---
updated-dependencies:
- dependency-name: pluggy
  dependency-version: 1.6.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump click from 8.2.0 to 8.2.1 (#368)

Bumps [click](https://github.com/pallets/click) from 8.2.0 to 8.2.1.
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.rst)
- [Commits](pallets/click@8.2.0...8.2.1)

---
updated-dependencies:
- dependency-name: click
  dependency-version: 8.2.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump typer from 0.15.3 to 0.16.0 (#371)

Bumps [typer](https://github.com/fastapi/typer) from 0.15.3 to 0.16.0.
- [Release notes](https://github.com/fastapi/typer/releases)
- [Changelog](https://github.com/fastapi/typer/blob/master/docs/release-notes.md)
- [Commits](fastapi/typer@0.15.3...0.16.0)

---
updated-dependencies:
- dependency-name: typer
  dependency-version: 0.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump requests from 2.32.3 to 2.32.4 (#372)

Bumps [requests](https://github.com/psf/requests) from 2.32.3 to 2.32.4.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](psf/requests@v2.32.3...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump urllib3 from 2.4.0 to 2.5.0 (#374)

Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](urllib3/urllib3@2.4.0...2.5.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.5.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump rpds-py from 0.24.0 to 0.26.0 (#375)

Bumps [rpds-py](https://github.com/crate-py/rpds) from 0.24.0 to 0.26.0.
- [Release notes](https://github.com/crate-py/rpds/releases)
- [Commits](crate-py/rpds@v0.24.0...v0.26.0)

---
updated-dependencies:
- dependency-name: rpds-py
  dependency-version: 0.26.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump cryptography from 44.0.3 to 45.0.5 (#376)

Bumps [cryptography](https://github.com/pyca/cryptography) from 44.0.3 to 45.0.5.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](pyca/cryptography@44.0.3...45.0.5)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 45.0.5
  dependency-type: indirect
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Migrate to uv

* Refactor error handling

* Various linter updates

* Dependency updates

* Update readme

* Update dependencies and pyproject

* Fix dependency

* Fix robot dependency

* Update versions

* Bump astral-sh/setup-uv from 6 to 7 (#388)

Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6 to 7.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](astral-sh/setup-uv@v6...v7)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* License header updates

* Update changelog

* Update dependabot config for uv

* Bump nac-yaml version

* 1.1.0 version bump

* Bump actions/upload-artifact from 4 to 5 (#391)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix lint workflow for fork prs

* Expose pabot's process option to nac-test cli (#393)

* Increase robot loglevel to debug when verbosity=DEBUG is used (#394)

* Add robotframework-jmespath dependency (#395)

* Update README to include jmespath and add test for 3rd party libs (#396)

* Add support for test case parallelization for capable suites (#390)

* Switch from pabot.main to pabot.main_program and handle exit codes (#400)

Change nac-test to use pabot's main_program() instead of main() to avoid
sys.exit() calls and properly handle exit codes. This allows nac-test to
control the exit behavior and return appropriate exit codes to the caller.

Key changes:
- Update run_pabot() to call pabot.pabot.main_program() instead of main()
- Change run_pabot() return type from None to int
- Return exit code from pabot execution
- Update CLI main() to capture and use exit code
- Remove try/except wrapper in CLI main() - let exceptions propagate
- Disable typer pretty exceptions for cleaner error output

Benefits:
- Proper exit code handling (test failures, errors, etc.)
- No unexpected sys.exit() calls
- Cleaner error messages without verbose typer tracebacks
- Better integration with CI/CD systems

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for passing Robot Framework options to nac-test (#399)

* Add support for passing Robot Framework options to nac-test

Users can now pass additional Robot Framework options directly to
nac-test, which are validated and appended to the pabot invocation.
This enables advanced use cases like custom variables, listeners,
and logging configuration without modifying nac-test's core options.

Key changes:
- Enable extra args in CLI via typer context settings
- Add parse_and_validate_extra_args() to validate Robot Framework options
- Reject pabot-specific options (--processes, --testlevelsplit, etc.)
- Reject datasources/test files in extra arguments
- Return exit code 252 for invalid extra arguments
- Separate pabot_args and robot_args for proper argument ordering
- Add comprehensive unit tests (14 tests covering all scenarios)
- Add type hints and fix all mypy errors
- Update CLI help text to document extra args feature

Implementation details:
- Uses pabot's parse_args() to validate options against Robot Framework
- Filters out datasources and pabot-specific options
- Appends validated args to robot_args before pabot invocation
- Proper error handling with logging and exit codes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Remove pabot.main_program changes from robot-args branch

This commit removes the pabot-specific changes (main_program, exit codes,
exception handling) that belong in the separate pabot-call branch. The
robot-args branch now focuses solely on the extra arguments feature.

Changes:
- Revert run_pabot() return type from int to None
- Use pabot.pabot.main() instead of main_program()
- Remove exit code handling (no return 252)
- Keep try/except in CLI main() for proper error handling
- Update tests to use pabot.pabot.main mock
- Update tests to expect exceptions instead of error codes

The extra args validation and appending logic remains unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Revert "Remove pabot.main_program changes from robot-args branch"

This reverts commit df21b98.

---------

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for chunking templates (#398)

* Update changelog and readms

* Update lock file

* Expand test coverage for chunk split test (#401)

* Fix typo in readme link

* Remove library version numbers from readme

* 1.2.0 version bump

* Support rendering on windows (#404)

* Bump actions/checkout from 5 to 6 (#402)

Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update changelog

* 1.2.1 version bump

* Bump actions/upload-artifact from 5 to 6 (#418)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: resolve all ruff linting errors and warnings

Fix code quality issues identified by ruff to ensure compliance with
project style guidelines and best practices.

Changes:
- Fix syntax error in pabot.py (space in != operator)
- Add missing filecmp import in test_integration.py
- Add proper exception chaining (from e) for B904 violations
- Rename unused loop variables to prefix with underscore (B007)
- Remove trailing whitespace from blank lines (W293)
- Modernize Union type annotations to use | operator (UP007)
- Remove unused Union import after migration to | syntax
- Exclude test fixture directories from ruff checks in pyproject.toml

All ruff checks now pass successfully.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix pabot module import in tests/unit/test_pabot_args.py

* no longer test for RESTinstance robot lib

* add fixture to set bogus ACI_xxx environment for nac-test to pass rendering tests

* add/fix --processes feature

* fix/add ordering_file logic to robot orchestrator

* fix/add passing extra cli args to robot orchestrator

* add integration test for extra args

* update README.md

* fix ruff config changes broken during merge conflict resolution

* fix: resolve all mypy type checking errors

This commit addresses 11 mypy type errors across 4 files:

- connection_utils.py: Add type annotations for dict parameters and
  update function signature to accept None values that are validated
- subprocess_runner.py: Remove unreachable code branch in output
  processing that was flagged due to redundant None check
- connection_broker.py: Add type annotations for testbed attribute,
  AsyncIterator return type, and assertion for loader result
- robot_writer.py: Remove duplicate method definition and add explicit
  type annotation to prevent incorrect type narrowing

All files now pass mypy strict type checking without errors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: restore custom_data handling in render_template for chunked templates

The refactoring that moved data conversion to initialization (for
performance) inadvertently broke the chunked template functionality
by not using the custom_data parameter when provided.

The render_template method now correctly checks if custom_data is
provided (used for chunked templates) and converts it on-demand,
otherwise uses the pre-converted self.template_data.

This fixes the test_nac_test_list_chunked test which was failing
after merging main into the feature branch.

Fixes functionality added in commits 18da546 and ced5983.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* ruff formatting fixes

* fix: add type stub dependencies to pre-commit mypy hook

The pre-commit mypy hook runs in an isolated environment and needs
type stubs explicitly specified via additional_dependencies. Without
these, mypy complains about missing type information for yaml, aiofiles,
and markdown modules.

Added:
- types-PyYAML>=6.0.12.20250822
- types-aiofiles>=24.1.0.20250822
- types-markdown>=3.8.0.20250809

This aligns the pre-commit environment with the project dependencies
and allows mypy to properly type-check imports from these libraries.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: add type annotations to unit test functions

Add proper type annotations to all test functions in tests/unit to
resolve mypy strict type checking errors. Changes include:

- Add -> None return type annotations to all test methods
- Add type annotations for mock parameters (mock_logger,
  mock_connection_class, etc.) using typing.Any
- Add explicit type annotation for connections list variable
- Add type: ignore comment for intentional type mismatch in test

This ensures tests pass mypy strict type checking while maintaining
test clarity and avoiding over-specification of mock types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller tests from shell environment variables

Add autouse fixture to clear all controller-related environment
variables (ACI_*, SDWAN_*, CC_*, MERAKI_*, FMC_*, ISE_*) before
each test in TestCombinedOrchestratorController.

This ensures tests run in a clean environment and results are not
influenced by the caller's shell environment, preventing false
failures when developer has controller credentials set in their
shell.

The fixture uses pytest's monkeypatch to safely remove environment
variables only for the duration of each test.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor: migrate integration test fixture to use monkeypatch

Replace manual environment variable setup/teardown with pytest's
monkeypatch fixture for safer and more robust test isolation.

Benefits of monkeypatch approach:
- Automatic cleanup guaranteed even if test fails
- Safe deletion with raising=False (no KeyError if var missing)
- Preserves and restores original environment variable values
- Less boilerplate code (no yield/try-finally needed)
- Thread-safe state management handled by pytest

The fixture now uses monkeypatch.setenv() which automatically saves
the original value (if any) and restores it after the test, ensuring
the caller's shell environment is never permanently modified.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller detection integration tests from shell environment

Add autouse fixture to clear all controller-related environment
variables before each test in TestControllerDetectionIntegration.

This prevents test failures when developers have controller credentials
set in their shell environment. Without this fix, tests would fail with
"Multiple controller credentials detected" errors when shell variables
conflicted with test-specific environment setup.

The fixture uses pytest's monkeypatch.delenv() with raising=False for
safe deletion that won't fail if a variable doesn't exist.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* add license headers

* add missing test fixture template for extra args test

* security: replace hardcoded /tmp with tempfile.gettempdir() in ConnectionBroker

Fix Bandit B108 vulnerability by using tempfile.gettempdir() instead of
hardcoded /tmp path for output_dir default value. This ensures
cross-platform compatibility and respects system-specific temporary
directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: add usedforsecurity=False to MD5 hash in AuthCache

Fix Bandit B324 vulnerability by explicitly marking MD5 usage as not for
security purposes. The hash is only used to generate cache filenames from
URLs, not for cryptographic security.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp references in emergency dump

Fix Bandit B108 vulnerabilities by:
- Using tempfile.gettempdir() instead of hardcoded /tmp path
- Dynamically checking if file is in temp directory instead of string matching "/tmp/"
- Updated docstrings and log messages to reflect system temp dir usage

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in AUTH_CACHE_DIR constant

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for AUTH_CACHE_DIR.
This ensures cross-platform compatibility and respects system-specific
temporary directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in batching reporter overflow dir

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for default
overflow directory. This ensures cross-platform compatibility while
still allowing override via NAC_TEST_OVERFLOW_DIR environment variable.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: enable Jinja2 autoescape to prevent XSS vulnerabilities

Fix Bandit B701 vulnerability by enabling autoescape for HTML, XML, and
.j2 files using select_autoescape(). This prevents potential XSS attacks
when rendering user-controlled data in HTML reports.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* gitignore bandit-security-report.json created during pipeline run

* Update readme cli help output

* rename robot/pabot integration test file

* Add netconf related packages and update dependencies

* 1.2.2 version bump

* refactor: centralize DEBUG_MODE constant for progressive disclosure

Consolidates the NAC_TEST_DEBUG environment variable check into a single
constant in core/constants.py, eliminating repeated inline checks.

Changes:
- Add DEBUG_MODE constant to nac_test/core/constants.py
- Update cli/main.py to use DEBUG_MODE for pretty_exceptions_enable
- Update combined_orchestrator.py to use DEBUG_MODE for exception handling
- Update batching_reporter.py to use DEBUG_MODE (2 locations)

This enables progressive disclosure: customers get clean error output by
default, while developers can set NAC_TEST_DEBUG=true for full exception
context and verbose tracebacks when debugging.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: danischm <danischm@cisco.com>
Co-authored-by: Oliver Boehmer <oli@spine.de>
Co-authored-by: Oliver Boehmer <oboehmer@cisco.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Justyna Chowaniec <79261946+juchowan@users.noreply.github.com>
oboehmer added a commit that referenced this pull request Mar 19, 2026
* Bump pluggy from 1.5.0 to 1.6.0 (#365)

Bumps [pluggy](https://github.com/pytest-dev/pluggy) from 1.5.0 to 1.6.0.
- [Changelog](https://github.com/pytest-dev/pluggy/blob/main/CHANGELOG.rst)
- [Commits](pytest-dev/pluggy@1.5.0...1.6.0)

---
updated-dependencies:
- dependency-name: pluggy
  dependency-version: 1.6.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump click from 8.2.0 to 8.2.1 (#368)

Bumps [click](https://github.com/pallets/click) from 8.2.0 to 8.2.1.
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.rst)
- [Commits](pallets/click@8.2.0...8.2.1)

---
updated-dependencies:
- dependency-name: click
  dependency-version: 8.2.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump typer from 0.15.3 to 0.16.0 (#371)

Bumps [typer](https://github.com/fastapi/typer) from 0.15.3 to 0.16.0.
- [Release notes](https://github.com/fastapi/typer/releases)
- [Changelog](https://github.com/fastapi/typer/blob/master/docs/release-notes.md)
- [Commits](fastapi/typer@0.15.3...0.16.0)

---
updated-dependencies:
- dependency-name: typer
  dependency-version: 0.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump requests from 2.32.3 to 2.32.4 (#372)

Bumps [requests](https://github.com/psf/requests) from 2.32.3 to 2.32.4.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](psf/requests@v2.32.3...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump urllib3 from 2.4.0 to 2.5.0 (#374)

Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](urllib3/urllib3@2.4.0...2.5.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.5.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump rpds-py from 0.24.0 to 0.26.0 (#375)

Bumps [rpds-py](https://github.com/crate-py/rpds) from 0.24.0 to 0.26.0.
- [Release notes](https://github.com/crate-py/rpds/releases)
- [Commits](crate-py/rpds@v0.24.0...v0.26.0)

---
updated-dependencies:
- dependency-name: rpds-py
  dependency-version: 0.26.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump cryptography from 44.0.3 to 45.0.5 (#376)

Bumps [cryptography](https://github.com/pyca/cryptography) from 44.0.3 to 45.0.5.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](pyca/cryptography@44.0.3...45.0.5)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 45.0.5
  dependency-type: indirect
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Migrate to uv

* Refactor error handling

* Various linter updates

* Dependency updates

* Update readme

* Update dependencies and pyproject

* Fix dependency

* Fix robot dependency

* Update versions

* Bump astral-sh/setup-uv from 6 to 7 (#388)

Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6 to 7.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](astral-sh/setup-uv@v6...v7)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* License header updates

* Update changelog

* Update dependabot config for uv

* Bump nac-yaml version

* 1.1.0 version bump

* Bump actions/upload-artifact from 4 to 5 (#391)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix lint workflow for fork prs

* Expose pabot's process option to nac-test cli (#393)

* Increase robot loglevel to debug when verbosity=DEBUG is used (#394)

* Add robotframework-jmespath dependency (#395)

* Update README to include jmespath and add test for 3rd party libs (#396)

* Add support for test case parallelization for capable suites (#390)

* Switch from pabot.main to pabot.main_program and handle exit codes (#400)

Change nac-test to use pabot's main_program() instead of main() to avoid
sys.exit() calls and properly handle exit codes. This allows nac-test to
control the exit behavior and return appropriate exit codes to the caller.

Key changes:
- Update run_pabot() to call pabot.pabot.main_program() instead of main()
- Change run_pabot() return type from None to int
- Return exit code from pabot execution
- Update CLI main() to capture and use exit code
- Remove try/except wrapper in CLI main() - let exceptions propagate
- Disable typer pretty exceptions for cleaner error output

Benefits:
- Proper exit code handling (test failures, errors, etc.)
- No unexpected sys.exit() calls
- Cleaner error messages without verbose typer tracebacks
- Better integration with CI/CD systems

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for passing Robot Framework options to nac-test (#399)

* Add support for passing Robot Framework options to nac-test

Users can now pass additional Robot Framework options directly to
nac-test, which are validated and appended to the pabot invocation.
This enables advanced use cases like custom variables, listeners,
and logging configuration without modifying nac-test's core options.

Key changes:
- Enable extra args in CLI via typer context settings
- Add parse_and_validate_extra_args() to validate Robot Framework options
- Reject pabot-specific options (--processes, --testlevelsplit, etc.)
- Reject datasources/test files in extra arguments
- Return exit code 252 for invalid extra arguments
- Separate pabot_args and robot_args for proper argument ordering
- Add comprehensive unit tests (14 tests covering all scenarios)
- Add type hints and fix all mypy errors
- Update CLI help text to document extra args feature

Implementation details:
- Uses pabot's parse_args() to validate options against Robot Framework
- Filters out datasources and pabot-specific options
- Appends validated args to robot_args before pabot invocation
- Proper error handling with logging and exit codes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Remove pabot.main_program changes from robot-args branch

This commit removes the pabot-specific changes (main_program, exit codes,
exception handling) that belong in the separate pabot-call branch. The
robot-args branch now focuses solely on the extra arguments feature.

Changes:
- Revert run_pabot() return type from int to None
- Use pabot.pabot.main() instead of main_program()
- Remove exit code handling (no return 252)
- Keep try/except in CLI main() for proper error handling
- Update tests to use pabot.pabot.main mock
- Update tests to expect exceptions instead of error codes

The extra args validation and appending logic remains unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Revert "Remove pabot.main_program changes from robot-args branch"

This reverts commit df21b98.

---------

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for chunking templates (#398)

* Update changelog and readms

* Update lock file

* Expand test coverage for chunk split test (#401)

* Fix typo in readme link

* Remove library version numbers from readme

* 1.2.0 version bump

* feat(path_setup): auto-discover pyats_common for test imports

Add find_pyats_common_parent() to search test directory tree for
pyats_common subdirectory and add its parent to PYTHONPATH. This
enables test files to use simple imports like:
  from pyats_common.apic_base_test import APICTestBase

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* add verbose option to pyats when running at DEBUG level, log pyats output as well when in DEBUG

* current state, not yet working

* add simple test for pipeline - WIP

* add integration tests and support for mock devices

* use easypy.run to invoke script

* do not assume a default CONTROLLER_TYPE

* remove assumption for CONTROLLER_TYPE being ACI in base_test too

* adjust test

* add some debug log statements

* add warning about potential issues with python3.11 on macOS

* connect using log_stdout=False

* fix simple test, and ruff formatting

* simple test changes, WIP

* Support rendering on windows (#404)

* Bump actions/checkout from 5 to 6 (#402)

Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update changelog

* 1.2.1 version bump

* update with mock flask server - WIP

* remove debug logs

* add mock-server to perform API testing in integration tests

* add integration tests for quicksilver-generated templates

* add type hints

* Bump actions/upload-artifact from 5 to 6 (#418)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* add sdwan mock api results

* adjust mock-server file, create mock-server test

* fix: resolve all ruff linting errors and warnings

Fix code quality issues identified by ruff to ensure compliance with
project style guidelines and best practices.

Changes:
- Fix syntax error in pabot.py (space in != operator)
- Add missing filecmp import in test_integration.py
- Add proper exception chaining (from e) for B904 violations
- Rename unused loop variables to prefix with underscore (B007)
- Remove trailing whitespace from blank lines (W293)
- Modernize Union type annotations to use | operator (UP007)
- Remove unused Union import after migration to | syntax
- Exclude test fixture directories from ruff checks in pyproject.toml

All ruff checks now pass successfully.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix pabot module import in tests/unit/test_pabot_args.py

* no longer test for RESTinstance robot lib

* add fixture to set bogus ACI_xxx environment for nac-test to pass rendering tests

* add/fix --processes feature

* fix/add ordering_file logic to robot orchestrator

* fix/add passing extra cli args to robot orchestrator

* add integration test for extra args

* update README.md

* fix ruff config changes broken during merge conflict resolution

* fix: resolve all mypy type checking errors

This commit addresses 11 mypy type errors across 4 files:

- connection_utils.py: Add type annotations for dict parameters and
  update function signature to accept None values that are validated
- subprocess_runner.py: Remove unreachable code branch in output
  processing that was flagged due to redundant None check
- connection_broker.py: Add type annotations for testbed attribute,
  AsyncIterator return type, and assertion for loader result
- robot_writer.py: Remove duplicate method definition and add explicit
  type annotation to prevent incorrect type narrowing

All files now pass mypy strict type checking without errors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: restore custom_data handling in render_template for chunked templates

The refactoring that moved data conversion to initialization (for
performance) inadvertently broke the chunked template functionality
by not using the custom_data parameter when provided.

The render_template method now correctly checks if custom_data is
provided (used for chunked templates) and converts it on-demand,
otherwise uses the pre-converted self.template_data.

This fixes the test_nac_test_list_chunked test which was failing
after merging main into the feature branch.

Fixes functionality added in commits 18da546 and ced5983.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* ruff formatting fixes

* fix: add type stub dependencies to pre-commit mypy hook

The pre-commit mypy hook runs in an isolated environment and needs
type stubs explicitly specified via additional_dependencies. Without
these, mypy complains about missing type information for yaml, aiofiles,
and markdown modules.

Added:
- types-PyYAML>=6.0.12.20250822
- types-aiofiles>=24.1.0.20250822
- types-markdown>=3.8.0.20250809

This aligns the pre-commit environment with the project dependencies
and allows mypy to properly type-check imports from these libraries.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: add type annotations to unit test functions

Add proper type annotations to all test functions in tests/unit to
resolve mypy strict type checking errors. Changes include:

- Add -> None return type annotations to all test methods
- Add type annotations for mock parameters (mock_logger,
  mock_connection_class, etc.) using typing.Any
- Add explicit type annotation for connections list variable
- Add type: ignore comment for intentional type mismatch in test

This ensures tests pass mypy strict type checking while maintaining
test clarity and avoiding over-specification of mock types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller tests from shell environment variables

Add autouse fixture to clear all controller-related environment
variables (ACI_*, SDWAN_*, CC_*, MERAKI_*, FMC_*, ISE_*) before
each test in TestCombinedOrchestratorController.

This ensures tests run in a clean environment and results are not
influenced by the caller's shell environment, preventing false
failures when developer has controller credentials set in their
shell.

The fixture uses pytest's monkeypatch to safely remove environment
variables only for the duration of each test.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor: migrate integration test fixture to use monkeypatch

Replace manual environment variable setup/teardown with pytest's
monkeypatch fixture for safer and more robust test isolation.

Benefits of monkeypatch approach:
- Automatic cleanup guaranteed even if test fails
- Safe deletion with raising=False (no KeyError if var missing)
- Preserves and restores original environment variable values
- Less boilerplate code (no yield/try-finally needed)
- Thread-safe state management handled by pytest

The fixture now uses monkeypatch.setenv() which automatically saves
the original value (if any) and restores it after the test, ensuring
the caller's shell environment is never permanently modified.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller detection integration tests from shell environment

Add autouse fixture to clear all controller-related environment
variables before each test in TestControllerDetectionIntegration.

This prevents test failures when developers have controller credentials
set in their shell environment. Without this fix, tests would fail with
"Multiple controller credentials detected" errors when shell variables
conflicted with test-specific environment setup.

The fixture uses pytest's monkeypatch.delenv() with raising=False for
safe deletion that won't fail if a variable doesn't exist.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* add license headers

* add missing test fixture template for extra args test

* security: replace hardcoded /tmp with tempfile.gettempdir() in ConnectionBroker

Fix Bandit B108 vulnerability by using tempfile.gettempdir() instead of
hardcoded /tmp path for output_dir default value. This ensures
cross-platform compatibility and respects system-specific temporary
directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: add usedforsecurity=False to MD5 hash in AuthCache

Fix Bandit B324 vulnerability by explicitly marking MD5 usage as not for
security purposes. The hash is only used to generate cache filenames from
URLs, not for cryptographic security.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp references in emergency dump

Fix Bandit B108 vulnerabilities by:
- Using tempfile.gettempdir() instead of hardcoded /tmp path
- Dynamically checking if file is in temp directory instead of string matching "/tmp/"
- Updated docstrings and log messages to reflect system temp dir usage

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in AUTH_CACHE_DIR constant

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for AUTH_CACHE_DIR.
This ensures cross-platform compatibility and respects system-specific
temporary directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in batching reporter overflow dir

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for default
overflow directory. This ensures cross-platform compatibility while
still allowing override via NAC_TEST_OVERFLOW_DIR environment variable.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: enable Jinja2 autoescape to prevent XSS vulnerabilities

Fix Bandit B701 vulnerability by enabling autoescape for HTML, XML, and
.j2 files using select_autoescape(). This prevents potential XSS attacks
when rendering user-controlled data in HTML reports.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* gitignore bandit-security-report.json created during pipeline run

* Update readme cli help output

* rename robot/pabot integration test file

* Add netconf related packages and update dependencies

* 1.2.2 version bump

* adjust and fix aci integration tests

* remove environment vars after testing

* fix license check

* remove unfinished tests

* use tmpdir

* add debugging for CI troubleshooting

* attempt to fix event loop issue in CI

* add more debug code to troubleshoot CI failure

* add missing nac-test-pyats-common  to CI pipeline

* sum up passed/failed for check (in case we have multiple results.json files)

* re-organize test case fixture directories

use a common base dir, and then add specific archs as subdirectories to avoid directory bloat in fixture directory

* Fix Python 3.12 asyncio compatibility with get_or_create_event_loop

Python 3.12 changed asyncio.get_event_loop() behavior to raise
RuntimeError when called from the main thread without an active event loop,
breaking async operations that run synchronous PyATS/Unicon calls via
loop.run_in_executor().

Previous behavior (Python 3.10-3.11):
- asyncio.get_event_loop() automatically created a new event loop if none existed

New behavior (Python 3.12+):
- asyncio.get_event_loop() raises RuntimeError if no event loop exists
- Must explicitly call asyncio.new_event_loop() and set_event_loop()

Solution:
Created get_or_create_event_loop() helper that handles both behaviors:
- Tries to get existing event loop
- If closed or RuntimeError, creates and sets a new loop
- Works across Python 3.10-3.12+

Replaced 9 instances of asyncio.get_event_loop() across 4 modules:
- nac_test/pyats_core/broker/connection_broker.py (3 calls)
- nac_test/pyats_core/common/ssh_base_test.py (3 calls)
- nac_test/pyats_core/ssh/connection_manager.py (2 calls)
- nac_test/pyats_core/reporting/multi_archive_generator.py (1 call)

These calls are used to run blocking Unicon operations (connect, disconnect,
execute) in thread pools via run_in_executor() to prevent blocking the
async event loop.

* add sdwan integration tests (both api and d2d)

* add license header

* test: remove test_mock_server.py - tests mock infrastructure, not business logic

These tests only verify that the MockAPIServer returns what it was
configured to return:
- test_mock_api_server_endpoint_matching: configures endpoints, asserts they return configured data
- test_nac_test_with_mock_api_complex_urls: same pattern with complex URLs
- test_nac_test_with_mock_api_dynamic: adds endpoint with response X, asserts response is X

This violates the principle: "What MUST NEVER be Tested: whether mocks
return what you told them to return."

The mock server is infrastructure to enable testing real business logic,
not something that needs its own test coverage.

* test: remove test_controller_detection_consistency - tests Python determinism

This test calls detect_controller_type() three times with identical
environment and asserts all results are equal. This tests whether Python
functions return consistent results when called with the same inputs -
which is testing Python's deterministic execution, not business logic.

A pure function will always return the same result for the same inputs.
Testing this adds no value unless there's caching or stateful behavior
that could cause inconsistency (there isn't).

Violates: "What MUST NEVER be Tested: Whether Python's standard library works"

* test: remove mock assertion from test_end_to_end_controller_detection

Removed the pattern that mocks EnvironmentValidator and asserts it was
called with the correct argument:

    with patch("...EnvironmentValidator") as mock_validator:
        orchestrator.validate_environment()
        mock_validator.validate_controller_env.assert_called_once_with("SDWAN")

This tests whether validate_environment() calls EnvironmentValidator with
the right argument - essentially testing "whether one-line wrapper functions
call the functions they wrap."

The real test is already done: assert orchestrator.controller_type == "SDWAN"
which validates the business logic (controller was correctly detected).

Violates: "What MUST NEVER be Tested: whether one-line wrapper functions
call the functions they wrap"

* fix(tests): remove conflicting copyright header and fix resource leak

mock_unicon.py changes:
- Removed Cisco proprietary copyright header (lines 5-7), keeping only MPL-2.0
- Fixed resource leak: file opened without context manager now uses 'with' statement

Before:
  states = yaml.safe_load(open(os.path.join(mock_data_dir, file))) or []

After:
  with open(os.path.join(mock_data_dir, file)) as f:
      states = yaml.safe_load(f) or []

* fix(tests): implement proper server startup and shutdown for MockAPIServer

mock_server.py changes:
- Replaced time.sleep(0.5) race condition with proper readiness polling
- Added _wait_for_server_ready() that polls until server responds or timeout
- Implemented proper stop() method using werkzeug.serving.make_server
- Added reset_endpoints() method to clear dynamic endpoints while preserving
  YAML-loaded baseline (enables test isolation with session-scoped fixture)
- Added SERVER_STARTUP_TIMEOUT_SECONDS and SERVER_POLL_INTERVAL_SECONDS constants

This fixes flaky test failures caused by server not being ready, and
prevents port conflicts from improper shutdown.

* fix(tests): add endpoint reset and isolated fixture for test isolation

conftest.py changes:
- Updated mock_api_server fixture to call reset_endpoints() after yield
- Added mock_api_server_isolated fixture (function-scoped) for tests that
  add dynamic endpoints, preventing cross-test pollution

The session-scoped mock_api_server now resets to baseline state between
tests, while mock_api_server_isolated provides per-test isolation.

* fix(tests): use absolute path and fix PEP8 naming in test_pyats_standard

test_pyats_standard.py changes:
- Fixed hardcoded relative path that breaks when run from different directories
  Now uses Path(__file__).parent to construct absolute path to mock_unicon.py
- Renamed classes tc_one -> TcOne, tc_two -> TcTwo (PEP8 CamelCase)
- Fixed decorator spacing: '@ aetest.test' -> '@aetest.test'

* fix(tests): replace debug prints with logging and use monkeypatch

test_integration_pyats.py changes:
- Replaced all print() debug statements with logger.debug() calls
- Moved 'import json' from inside function to module level
- Refactored environment variable handling to use monkeypatch.setenv()
  instead of manual os.environ manipulation with try/finally
- Removed commented-out debug code for static output directories

This improves test maintainability and ensures proper cleanup via
pytest's monkeypatch fixture.

* fix(tests): modernize type hints and use monkeypatch in robot_pabot tests

test_integration_robot_pabot.py changes:
- Changed all tmpdir: str parameters to tmp_path: Path (modern pytest fixture)
- Refactored environment variable handling to use monkeypatch.setenv()
  instead of manual os.environ with try/finally cleanup
- Updated fixture references from tmpdir to tmp_path throughout
- Used Path methods (.exists(), .touch()) instead of os.path equivalents

This improves type safety and ensures proper test isolation via pytest's
automatic cleanup of monkeypatched environment variables.

* fix(tests): replace obfuscated code and emojis in PyATS quicksilver tests

templates_pyats_qs test changes (3 files):
- verify_sdwanmanager_all_sd_wan_edge_configurations_are_in_sync.py
- verify_iosxe_all_sd_wan_control_connections_are_up.py
- verify_aci_apic_appliance_operational_status.py

Changes applied to all:
- Replaced chr(10) with '\n' for clarity
- Replaced emoji markers with text: ❌ -> [FAIL], ✅ -> [PASS]

This prevents encoding issues in CI logs and improves code readability.

* fix(tests): extract f-string join to variable for Python 3.11 compatibility

Python 3.11 does not allow backslash escapes inside f-string expressions.
The previous commit replaced chr(10) with '\n' but left it inside the
f-string expression, causing a SyntaxError.

This fix extracts the join operation to a separate variable before using
it in the f-string:

    failures_text = '\n'.join(failures)
    f"{failures_text}\n\n"

* fix(tests): add proxy bypass for localhost in integration tests

Add session-scoped autouse fixture to ensure 127.0.0.1 is included in
the no_proxy/NO_PROXY environment variables. This prevents the mock API
server requests from being routed through corporate proxies, which was
causing 504 Gateway Timeout errors in environments with proxy configured.

The fixture preserves original proxy settings and restores them after
the test session completes.

* refactor(tests): split robot_pabot tests into focused modules

Split the 493-line test_integration_robot_pabot.py into 4 focused
test modules following Single Responsibility Principle:

- test_cli_basic.py: Basic CLI execution tests (6 tests)
- test_cli_rendering.py: Template rendering tests (8 tests)
- test_cli_ordering.py: Robot test ordering tests (4 tests)
- test_cli_extra_args.py: Extra arguments tests (5 tests)

Improvements:
- Added Google-style docstrings to all 23 test functions
- Renamed generic test names to descriptive names
- Added assertion messages to all assert statements
- Extracted magic number to named constant (ROBOT_ARGUMENT_ERROR_EXIT_CODE)

* add management_ip_variable to test fixture data

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: danischm <danischm@cisco.com>
Co-authored-by: Oliver Boehmer <oli@spine.de>
Co-authored-by: Oliver Boehmer <oboehmer@cisco.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Justyna Chowaniec <79261946+juchowan@users.noreply.github.com>
oboehmer added a commit that referenced this pull request Mar 19, 2026
* Bump pluggy from 1.5.0 to 1.6.0 (#365)

Bumps [pluggy](https://github.com/pytest-dev/pluggy) from 1.5.0 to 1.6.0.
- [Changelog](https://github.com/pytest-dev/pluggy/blob/main/CHANGELOG.rst)
- [Commits](pytest-dev/pluggy@1.5.0...1.6.0)

---
updated-dependencies:
- dependency-name: pluggy
  dependency-version: 1.6.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump click from 8.2.0 to 8.2.1 (#368)

Bumps [click](https://github.com/pallets/click) from 8.2.0 to 8.2.1.
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.rst)
- [Commits](pallets/click@8.2.0...8.2.1)

---
updated-dependencies:
- dependency-name: click
  dependency-version: 8.2.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump typer from 0.15.3 to 0.16.0 (#371)

Bumps [typer](https://github.com/fastapi/typer) from 0.15.3 to 0.16.0.
- [Release notes](https://github.com/fastapi/typer/releases)
- [Changelog](https://github.com/fastapi/typer/blob/master/docs/release-notes.md)
- [Commits](fastapi/typer@0.15.3...0.16.0)

---
updated-dependencies:
- dependency-name: typer
  dependency-version: 0.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump requests from 2.32.3 to 2.32.4 (#372)

Bumps [requests](https://github.com/psf/requests) from 2.32.3 to 2.32.4.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](psf/requests@v2.32.3...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump urllib3 from 2.4.0 to 2.5.0 (#374)

Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](urllib3/urllib3@2.4.0...2.5.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.5.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump rpds-py from 0.24.0 to 0.26.0 (#375)

Bumps [rpds-py](https://github.com/crate-py/rpds) from 0.24.0 to 0.26.0.
- [Release notes](https://github.com/crate-py/rpds/releases)
- [Commits](crate-py/rpds@v0.24.0...v0.26.0)

---
updated-dependencies:
- dependency-name: rpds-py
  dependency-version: 0.26.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump cryptography from 44.0.3 to 45.0.5 (#376)

Bumps [cryptography](https://github.com/pyca/cryptography) from 44.0.3 to 45.0.5.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](pyca/cryptography@44.0.3...45.0.5)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 45.0.5
  dependency-type: indirect
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Migrate to uv

* Refactor error handling

* Various linter updates

* Dependency updates

* Update readme

* Update dependencies and pyproject

* Fix dependency

* Fix robot dependency

* Update versions

* Bump astral-sh/setup-uv from 6 to 7 (#388)

Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6 to 7.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](astral-sh/setup-uv@v6...v7)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* License header updates

* Update changelog

* Update dependabot config for uv

* Bump nac-yaml version

* 1.1.0 version bump

* Bump actions/upload-artifact from 4 to 5 (#391)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix lint workflow for fork prs

* Expose pabot's process option to nac-test cli (#393)

* Increase robot loglevel to debug when verbosity=DEBUG is used (#394)

* Add robotframework-jmespath dependency (#395)

* Update README to include jmespath and add test for 3rd party libs (#396)

* Add support for test case parallelization for capable suites (#390)

* Switch from pabot.main to pabot.main_program and handle exit codes (#400)

Change nac-test to use pabot's main_program() instead of main() to avoid
sys.exit() calls and properly handle exit codes. This allows nac-test to
control the exit behavior and return appropriate exit codes to the caller.

Key changes:
- Update run_pabot() to call pabot.pabot.main_program() instead of main()
- Change run_pabot() return type from None to int
- Return exit code from pabot execution
- Update CLI main() to capture and use exit code
- Remove try/except wrapper in CLI main() - let exceptions propagate
- Disable typer pretty exceptions for cleaner error output

Benefits:
- Proper exit code handling (test failures, errors, etc.)
- No unexpected sys.exit() calls
- Cleaner error messages without verbose typer tracebacks
- Better integration with CI/CD systems

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for passing Robot Framework options to nac-test (#399)

* Add support for passing Robot Framework options to nac-test

Users can now pass additional Robot Framework options directly to
nac-test, which are validated and appended to the pabot invocation.
This enables advanced use cases like custom variables, listeners,
and logging configuration without modifying nac-test's core options.

Key changes:
- Enable extra args in CLI via typer context settings
- Add parse_and_validate_extra_args() to validate Robot Framework options
- Reject pabot-specific options (--processes, --testlevelsplit, etc.)
- Reject datasources/test files in extra arguments
- Return exit code 252 for invalid extra arguments
- Separate pabot_args and robot_args for proper argument ordering
- Add comprehensive unit tests (14 tests covering all scenarios)
- Add type hints and fix all mypy errors
- Update CLI help text to document extra args feature

Implementation details:
- Uses pabot's parse_args() to validate options against Robot Framework
- Filters out datasources and pabot-specific options
- Appends validated args to robot_args before pabot invocation
- Proper error handling with logging and exit codes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Remove pabot.main_program changes from robot-args branch

This commit removes the pabot-specific changes (main_program, exit codes,
exception handling) that belong in the separate pabot-call branch. The
robot-args branch now focuses solely on the extra arguments feature.

Changes:
- Revert run_pabot() return type from int to None
- Use pabot.pabot.main() instead of main_program()
- Remove exit code handling (no return 252)
- Keep try/except in CLI main() for proper error handling
- Update tests to use pabot.pabot.main mock
- Update tests to expect exceptions instead of error codes

The extra args validation and appending logic remains unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Revert "Remove pabot.main_program changes from robot-args branch"

This reverts commit df21b98.

---------

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for chunking templates (#398)

* Update changelog and readms

* Update lock file

* Expand test coverage for chunk split test (#401)

* Fix typo in readme link

* Remove library version numbers from readme

* 1.2.0 version bump

* Support rendering on windows (#404)

* Bump actions/checkout from 5 to 6 (#402)

Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update changelog

* 1.2.1 version bump

* Bump actions/upload-artifact from 5 to 6 (#418)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: resolve all ruff linting errors and warnings

Fix code quality issues identified by ruff to ensure compliance with
project style guidelines and best practices.

Changes:
- Fix syntax error in pabot.py (space in != operator)
- Add missing filecmp import in test_integration.py
- Add proper exception chaining (from e) for B904 violations
- Rename unused loop variables to prefix with underscore (B007)
- Remove trailing whitespace from blank lines (W293)
- Modernize Union type annotations to use | operator (UP007)
- Remove unused Union import after migration to | syntax
- Exclude test fixture directories from ruff checks in pyproject.toml

All ruff checks now pass successfully.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix pabot module import in tests/unit/test_pabot_args.py

* no longer test for RESTinstance robot lib

* add fixture to set bogus ACI_xxx environment for nac-test to pass rendering tests

* add/fix --processes feature

* fix/add ordering_file logic to robot orchestrator

* fix/add passing extra cli args to robot orchestrator

* add integration test for extra args

* update README.md

* fix ruff config changes broken during merge conflict resolution

* fix: resolve all mypy type checking errors

This commit addresses 11 mypy type errors across 4 files:

- connection_utils.py: Add type annotations for dict parameters and
  update function signature to accept None values that are validated
- subprocess_runner.py: Remove unreachable code branch in output
  processing that was flagged due to redundant None check
- connection_broker.py: Add type annotations for testbed attribute,
  AsyncIterator return type, and assertion for loader result
- robot_writer.py: Remove duplicate method definition and add explicit
  type annotation to prevent incorrect type narrowing

All files now pass mypy strict type checking without errors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: restore custom_data handling in render_template for chunked templates

The refactoring that moved data conversion to initialization (for
performance) inadvertently broke the chunked template functionality
by not using the custom_data parameter when provided.

The render_template method now correctly checks if custom_data is
provided (used for chunked templates) and converts it on-demand,
otherwise uses the pre-converted self.template_data.

This fixes the test_nac_test_list_chunked test which was failing
after merging main into the feature branch.

Fixes functionality added in commits 18da546 and ced5983.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* ruff formatting fixes

* fix: add type stub dependencies to pre-commit mypy hook

The pre-commit mypy hook runs in an isolated environment and needs
type stubs explicitly specified via additional_dependencies. Without
these, mypy complains about missing type information for yaml, aiofiles,
and markdown modules.

Added:
- types-PyYAML>=6.0.12.20250822
- types-aiofiles>=24.1.0.20250822
- types-markdown>=3.8.0.20250809

This aligns the pre-commit environment with the project dependencies
and allows mypy to properly type-check imports from these libraries.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: add type annotations to unit test functions

Add proper type annotations to all test functions in tests/unit to
resolve mypy strict type checking errors. Changes include:

- Add -> None return type annotations to all test methods
- Add type annotations for mock parameters (mock_logger,
  mock_connection_class, etc.) using typing.Any
- Add explicit type annotation for connections list variable
- Add type: ignore comment for intentional type mismatch in test

This ensures tests pass mypy strict type checking while maintaining
test clarity and avoiding over-specification of mock types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller tests from shell environment variables

Add autouse fixture to clear all controller-related environment
variables (ACI_*, SDWAN_*, CC_*, MERAKI_*, FMC_*, ISE_*) before
each test in TestCombinedOrchestratorController.

This ensures tests run in a clean environment and results are not
influenced by the caller's shell environment, preventing false
failures when developer has controller credentials set in their
shell.

The fixture uses pytest's monkeypatch to safely remove environment
variables only for the duration of each test.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor: migrate integration test fixture to use monkeypatch

Replace manual environment variable setup/teardown with pytest's
monkeypatch fixture for safer and more robust test isolation.

Benefits of monkeypatch approach:
- Automatic cleanup guaranteed even if test fails
- Safe deletion with raising=False (no KeyError if var missing)
- Preserves and restores original environment variable values
- Less boilerplate code (no yield/try-finally needed)
- Thread-safe state management handled by pytest

The fixture now uses monkeypatch.setenv() which automatically saves
the original value (if any) and restores it after the test, ensuring
the caller's shell environment is never permanently modified.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller detection integration tests from shell environment

Add autouse fixture to clear all controller-related environment
variables before each test in TestControllerDetectionIntegration.

This prevents test failures when developers have controller credentials
set in their shell environment. Without this fix, tests would fail with
"Multiple controller credentials detected" errors when shell variables
conflicted with test-specific environment setup.

The fixture uses pytest's monkeypatch.delenv() with raising=False for
safe deletion that won't fail if a variable doesn't exist.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* add license headers

* add missing test fixture template for extra args test

* security: replace hardcoded /tmp with tempfile.gettempdir() in ConnectionBroker

Fix Bandit B108 vulnerability by using tempfile.gettempdir() instead of
hardcoded /tmp path for output_dir default value. This ensures
cross-platform compatibility and respects system-specific temporary
directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: add usedforsecurity=False to MD5 hash in AuthCache

Fix Bandit B324 vulnerability by explicitly marking MD5 usage as not for
security purposes. The hash is only used to generate cache filenames from
URLs, not for cryptographic security.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp references in emergency dump

Fix Bandit B108 vulnerabilities by:
- Using tempfile.gettempdir() instead of hardcoded /tmp path
- Dynamically checking if file is in temp directory instead of string matching "/tmp/"
- Updated docstrings and log messages to reflect system temp dir usage

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in AUTH_CACHE_DIR constant

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for AUTH_CACHE_DIR.
This ensures cross-platform compatibility and respects system-specific
temporary directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in batching reporter overflow dir

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for default
overflow directory. This ensures cross-platform compatibility while
still allowing override via NAC_TEST_OVERFLOW_DIR environment variable.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: enable Jinja2 autoescape to prevent XSS vulnerabilities

Fix Bandit B701 vulnerability by enabling autoescape for HTML, XML, and
.j2 files using select_autoescape(). This prevents potential XSS attacks
when rendering user-controlled data in HTML reports.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* gitignore bandit-security-report.json created during pipeline run

* Update readme cli help output

* rename robot/pabot integration test file

* Add netconf related packages and update dependencies

* 1.2.2 version bump

* refactor: centralize DEBUG_MODE constant for progressive disclosure

Consolidates the NAC_TEST_DEBUG environment variable check into a single
constant in core/constants.py, eliminating repeated inline checks.

Changes:
- Add DEBUG_MODE constant to nac_test/core/constants.py
- Update cli/main.py to use DEBUG_MODE for pretty_exceptions_enable
- Update combined_orchestrator.py to use DEBUG_MODE for exception handling
- Update batching_reporter.py to use DEBUG_MODE (2 locations)

This enables progressive disclosure: customers get clean error output by
default, while developers can set NAC_TEST_DEBUG=true for full exception
context and verbose tracebacks when debugging.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: danischm <danischm@cisco.com>
Co-authored-by: Oliver Boehmer <oli@spine.de>
Co-authored-by: Oliver Boehmer <oboehmer@cisco.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Justyna Chowaniec <79261946+juchowan@users.noreply.github.com>
oboehmer added a commit that referenced this pull request Mar 19, 2026
* Bump pluggy from 1.5.0 to 1.6.0 (#365)

Bumps [pluggy](https://github.com/pytest-dev/pluggy) from 1.5.0 to 1.6.0.
- [Changelog](https://github.com/pytest-dev/pluggy/blob/main/CHANGELOG.rst)
- [Commits](pytest-dev/pluggy@1.5.0...1.6.0)

---
updated-dependencies:
- dependency-name: pluggy
  dependency-version: 1.6.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump click from 8.2.0 to 8.2.1 (#368)

Bumps [click](https://github.com/pallets/click) from 8.2.0 to 8.2.1.
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.rst)
- [Commits](pallets/click@8.2.0...8.2.1)

---
updated-dependencies:
- dependency-name: click
  dependency-version: 8.2.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump typer from 0.15.3 to 0.16.0 (#371)

Bumps [typer](https://github.com/fastapi/typer) from 0.15.3 to 0.16.0.
- [Release notes](https://github.com/fastapi/typer/releases)
- [Changelog](https://github.com/fastapi/typer/blob/master/docs/release-notes.md)
- [Commits](fastapi/typer@0.15.3...0.16.0)

---
updated-dependencies:
- dependency-name: typer
  dependency-version: 0.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump requests from 2.32.3 to 2.32.4 (#372)

Bumps [requests](https://github.com/psf/requests) from 2.32.3 to 2.32.4.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](psf/requests@v2.32.3...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump urllib3 from 2.4.0 to 2.5.0 (#374)

Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](urllib3/urllib3@2.4.0...2.5.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.5.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump rpds-py from 0.24.0 to 0.26.0 (#375)

Bumps [rpds-py](https://github.com/crate-py/rpds) from 0.24.0 to 0.26.0.
- [Release notes](https://github.com/crate-py/rpds/releases)
- [Commits](crate-py/rpds@v0.24.0...v0.26.0)

---
updated-dependencies:
- dependency-name: rpds-py
  dependency-version: 0.26.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump cryptography from 44.0.3 to 45.0.5 (#376)

Bumps [cryptography](https://github.com/pyca/cryptography) from 44.0.3 to 45.0.5.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](pyca/cryptography@44.0.3...45.0.5)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 45.0.5
  dependency-type: indirect
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Migrate to uv

* Refactor error handling

* Various linter updates

* Dependency updates

* Update readme

* Update dependencies and pyproject

* Fix dependency

* Fix robot dependency

* Update versions

* Bump astral-sh/setup-uv from 6 to 7 (#388)

Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6 to 7.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](astral-sh/setup-uv@v6...v7)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* License header updates

* Update changelog

* Update dependabot config for uv

* Bump nac-yaml version

* 1.1.0 version bump

* Bump actions/upload-artifact from 4 to 5 (#391)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix lint workflow for fork prs

* Expose pabot's process option to nac-test cli (#393)

* Increase robot loglevel to debug when verbosity=DEBUG is used (#394)

* Add robotframework-jmespath dependency (#395)

* Update README to include jmespath and add test for 3rd party libs (#396)

* Add support for test case parallelization for capable suites (#390)

* Switch from pabot.main to pabot.main_program and handle exit codes (#400)

Change nac-test to use pabot's main_program() instead of main() to avoid
sys.exit() calls and properly handle exit codes. This allows nac-test to
control the exit behavior and return appropriate exit codes to the caller.

Key changes:
- Update run_pabot() to call pabot.pabot.main_program() instead of main()
- Change run_pabot() return type from None to int
- Return exit code from pabot execution
- Update CLI main() to capture and use exit code
- Remove try/except wrapper in CLI main() - let exceptions propagate
- Disable typer pretty exceptions for cleaner error output

Benefits:
- Proper exit code handling (test failures, errors, etc.)
- No unexpected sys.exit() calls
- Cleaner error messages without verbose typer tracebacks
- Better integration with CI/CD systems

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for passing Robot Framework options to nac-test (#399)

* Add support for passing Robot Framework options to nac-test

Users can now pass additional Robot Framework options directly to
nac-test, which are validated and appended to the pabot invocation.
This enables advanced use cases like custom variables, listeners,
and logging configuration without modifying nac-test's core options.

Key changes:
- Enable extra args in CLI via typer context settings
- Add parse_and_validate_extra_args() to validate Robot Framework options
- Reject pabot-specific options (--processes, --testlevelsplit, etc.)
- Reject datasources/test files in extra arguments
- Return exit code 252 for invalid extra arguments
- Separate pabot_args and robot_args for proper argument ordering
- Add comprehensive unit tests (14 tests covering all scenarios)
- Add type hints and fix all mypy errors
- Update CLI help text to document extra args feature

Implementation details:
- Uses pabot's parse_args() to validate options against Robot Framework
- Filters out datasources and pabot-specific options
- Appends validated args to robot_args before pabot invocation
- Proper error handling with logging and exit codes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Remove pabot.main_program changes from robot-args branch

This commit removes the pabot-specific changes (main_program, exit codes,
exception handling) that belong in the separate pabot-call branch. The
robot-args branch now focuses solely on the extra arguments feature.

Changes:
- Revert run_pabot() return type from int to None
- Use pabot.pabot.main() instead of main_program()
- Remove exit code handling (no return 252)
- Keep try/except in CLI main() for proper error handling
- Update tests to use pabot.pabot.main mock
- Update tests to expect exceptions instead of error codes

The extra args validation and appending logic remains unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Revert "Remove pabot.main_program changes from robot-args branch"

This reverts commit df21b98.

---------

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for chunking templates (#398)

* Update changelog and readms

* Update lock file

* Expand test coverage for chunk split test (#401)

* Fix typo in readme link

* Remove library version numbers from readme

* 1.2.0 version bump

* feat(path_setup): auto-discover pyats_common for test imports

Add find_pyats_common_parent() to search test directory tree for
pyats_common subdirectory and add its parent to PYTHONPATH. This
enables test files to use simple imports like:
  from pyats_common.apic_base_test import APICTestBase

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* add verbose option to pyats when running at DEBUG level, log pyats output as well when in DEBUG

* current state, not yet working

* add simple test for pipeline - WIP

* add integration tests and support for mock devices

* use easypy.run to invoke script

* do not assume a default CONTROLLER_TYPE

* remove assumption for CONTROLLER_TYPE being ACI in base_test too

* adjust test

* add some debug log statements

* add warning about potential issues with python3.11 on macOS

* connect using log_stdout=False

* fix simple test, and ruff formatting

* simple test changes, WIP

* Support rendering on windows (#404)

* Bump actions/checkout from 5 to 6 (#402)

Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update changelog

* 1.2.1 version bump

* update with mock flask server - WIP

* remove debug logs

* add mock-server to perform API testing in integration tests

* add integration tests for quicksilver-generated templates

* add type hints

* Bump actions/upload-artifact from 5 to 6 (#418)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* add sdwan mock api results

* adjust mock-server file, create mock-server test

* fix: resolve all ruff linting errors and warnings

Fix code quality issues identified by ruff to ensure compliance with
project style guidelines and best practices.

Changes:
- Fix syntax error in pabot.py (space in != operator)
- Add missing filecmp import in test_integration.py
- Add proper exception chaining (from e) for B904 violations
- Rename unused loop variables to prefix with underscore (B007)
- Remove trailing whitespace from blank lines (W293)
- Modernize Union type annotations to use | operator (UP007)
- Remove unused Union import after migration to | syntax
- Exclude test fixture directories from ruff checks in pyproject.toml

All ruff checks now pass successfully.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix pabot module import in tests/unit/test_pabot_args.py

* no longer test for RESTinstance robot lib

* add fixture to set bogus ACI_xxx environment for nac-test to pass rendering tests

* add/fix --processes feature

* fix/add ordering_file logic to robot orchestrator

* fix/add passing extra cli args to robot orchestrator

* add integration test for extra args

* update README.md

* fix ruff config changes broken during merge conflict resolution

* fix: resolve all mypy type checking errors

This commit addresses 11 mypy type errors across 4 files:

- connection_utils.py: Add type annotations for dict parameters and
  update function signature to accept None values that are validated
- subprocess_runner.py: Remove unreachable code branch in output
  processing that was flagged due to redundant None check
- connection_broker.py: Add type annotations for testbed attribute,
  AsyncIterator return type, and assertion for loader result
- robot_writer.py: Remove duplicate method definition and add explicit
  type annotation to prevent incorrect type narrowing

All files now pass mypy strict type checking without errors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: restore custom_data handling in render_template for chunked templates

The refactoring that moved data conversion to initialization (for
performance) inadvertently broke the chunked template functionality
by not using the custom_data parameter when provided.

The render_template method now correctly checks if custom_data is
provided (used for chunked templates) and converts it on-demand,
otherwise uses the pre-converted self.template_data.

This fixes the test_nac_test_list_chunked test which was failing
after merging main into the feature branch.

Fixes functionality added in commits 18da546 and ced5983.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* ruff formatting fixes

* fix: add type stub dependencies to pre-commit mypy hook

The pre-commit mypy hook runs in an isolated environment and needs
type stubs explicitly specified via additional_dependencies. Without
these, mypy complains about missing type information for yaml, aiofiles,
and markdown modules.

Added:
- types-PyYAML>=6.0.12.20250822
- types-aiofiles>=24.1.0.20250822
- types-markdown>=3.8.0.20250809

This aligns the pre-commit environment with the project dependencies
and allows mypy to properly type-check imports from these libraries.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: add type annotations to unit test functions

Add proper type annotations to all test functions in tests/unit to
resolve mypy strict type checking errors. Changes include:

- Add -> None return type annotations to all test methods
- Add type annotations for mock parameters (mock_logger,
  mock_connection_class, etc.) using typing.Any
- Add explicit type annotation for connections list variable
- Add type: ignore comment for intentional type mismatch in test

This ensures tests pass mypy strict type checking while maintaining
test clarity and avoiding over-specification of mock types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller tests from shell environment variables

Add autouse fixture to clear all controller-related environment
variables (ACI_*, SDWAN_*, CC_*, MERAKI_*, FMC_*, ISE_*) before
each test in TestCombinedOrchestratorController.

This ensures tests run in a clean environment and results are not
influenced by the caller's shell environment, preventing false
failures when developer has controller credentials set in their
shell.

The fixture uses pytest's monkeypatch to safely remove environment
variables only for the duration of each test.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor: migrate integration test fixture to use monkeypatch

Replace manual environment variable setup/teardown with pytest's
monkeypatch fixture for safer and more robust test isolation.

Benefits of monkeypatch approach:
- Automatic cleanup guaranteed even if test fails
- Safe deletion with raising=False (no KeyError if var missing)
- Preserves and restores original environment variable values
- Less boilerplate code (no yield/try-finally needed)
- Thread-safe state management handled by pytest

The fixture now uses monkeypatch.setenv() which automatically saves
the original value (if any) and restores it after the test, ensuring
the caller's shell environment is never permanently modified.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller detection integration tests from shell environment

Add autouse fixture to clear all controller-related environment
variables before each test in TestControllerDetectionIntegration.

This prevents test failures when developers have controller credentials
set in their shell environment. Without this fix, tests would fail with
"Multiple controller credentials detected" errors when shell variables
conflicted with test-specific environment setup.

The fixture uses pytest's monkeypatch.delenv() with raising=False for
safe deletion that won't fail if a variable doesn't exist.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* add license headers

* add missing test fixture template for extra args test

* security: replace hardcoded /tmp with tempfile.gettempdir() in ConnectionBroker

Fix Bandit B108 vulnerability by using tempfile.gettempdir() instead of
hardcoded /tmp path for output_dir default value. This ensures
cross-platform compatibility and respects system-specific temporary
directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: add usedforsecurity=False to MD5 hash in AuthCache

Fix Bandit B324 vulnerability by explicitly marking MD5 usage as not for
security purposes. The hash is only used to generate cache filenames from
URLs, not for cryptographic security.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp references in emergency dump

Fix Bandit B108 vulnerabilities by:
- Using tempfile.gettempdir() instead of hardcoded /tmp path
- Dynamically checking if file is in temp directory instead of string matching "/tmp/"
- Updated docstrings and log messages to reflect system temp dir usage

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in AUTH_CACHE_DIR constant

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for AUTH_CACHE_DIR.
This ensures cross-platform compatibility and respects system-specific
temporary directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in batching reporter overflow dir

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for default
overflow directory. This ensures cross-platform compatibility while
still allowing override via NAC_TEST_OVERFLOW_DIR environment variable.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: enable Jinja2 autoescape to prevent XSS vulnerabilities

Fix Bandit B701 vulnerability by enabling autoescape for HTML, XML, and
.j2 files using select_autoescape(). This prevents potential XSS attacks
when rendering user-controlled data in HTML reports.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* gitignore bandit-security-report.json created during pipeline run

* Update readme cli help output

* rename robot/pabot integration test file

* Add netconf related packages and update dependencies

* 1.2.2 version bump

* adjust and fix aci integration tests

* remove environment vars after testing

* fix license check

* remove unfinished tests

* use tmpdir

* add debugging for CI troubleshooting

* attempt to fix event loop issue in CI

* add more debug code to troubleshoot CI failure

* add missing nac-test-pyats-common  to CI pipeline

* sum up passed/failed for check (in case we have multiple results.json files)

* re-organize test case fixture directories

use a common base dir, and then add specific archs as subdirectories to avoid directory bloat in fixture directory

* Fix Python 3.12 asyncio compatibility with get_or_create_event_loop

Python 3.12 changed asyncio.get_event_loop() behavior to raise
RuntimeError when called from the main thread without an active event loop,
breaking async operations that run synchronous PyATS/Unicon calls via
loop.run_in_executor().

Previous behavior (Python 3.10-3.11):
- asyncio.get_event_loop() automatically created a new event loop if none existed

New behavior (Python 3.12+):
- asyncio.get_event_loop() raises RuntimeError if no event loop exists
- Must explicitly call asyncio.new_event_loop() and set_event_loop()

Solution:
Created get_or_create_event_loop() helper that handles both behaviors:
- Tries to get existing event loop
- If closed or RuntimeError, creates and sets a new loop
- Works across Python 3.10-3.12+

Replaced 9 instances of asyncio.get_event_loop() across 4 modules:
- nac_test/pyats_core/broker/connection_broker.py (3 calls)
- nac_test/pyats_core/common/ssh_base_test.py (3 calls)
- nac_test/pyats_core/ssh/connection_manager.py (2 calls)
- nac_test/pyats_core/reporting/multi_archive_generator.py (1 call)

These calls are used to run blocking Unicon operations (connect, disconnect,
execute) in thread pools via run_in_executor() to prevent blocking the
async event loop.

* add sdwan integration tests (both api and d2d)

* add license header

* test: remove test_mock_server.py - tests mock infrastructure, not business logic

These tests only verify that the MockAPIServer returns what it was
configured to return:
- test_mock_api_server_endpoint_matching: configures endpoints, asserts they return configured data
- test_nac_test_with_mock_api_complex_urls: same pattern with complex URLs
- test_nac_test_with_mock_api_dynamic: adds endpoint with response X, asserts response is X

This violates the principle: "What MUST NEVER be Tested: whether mocks
return what you told them to return."

The mock server is infrastructure to enable testing real business logic,
not something that needs its own test coverage.

* test: remove test_controller_detection_consistency - tests Python determinism

This test calls detect_controller_type() three times with identical
environment and asserts all results are equal. This tests whether Python
functions return consistent results when called with the same inputs -
which is testing Python's deterministic execution, not business logic.

A pure function will always return the same result for the same inputs.
Testing this adds no value unless there's caching or stateful behavior
that could cause inconsistency (there isn't).

Violates: "What MUST NEVER be Tested: Whether Python's standard library works"

* test: remove mock assertion from test_end_to_end_controller_detection

Removed the pattern that mocks EnvironmentValidator and asserts it was
called with the correct argument:

    with patch("...EnvironmentValidator") as mock_validator:
        orchestrator.validate_environment()
        mock_validator.validate_controller_env.assert_called_once_with("SDWAN")

This tests whether validate_environment() calls EnvironmentValidator with
the right argument - essentially testing "whether one-line wrapper functions
call the functions they wrap."

The real test is already done: assert orchestrator.controller_type == "SDWAN"
which validates the business logic (controller was correctly detected).

Violates: "What MUST NEVER be Tested: whether one-line wrapper functions
call the functions they wrap"

* fix(tests): remove conflicting copyright header and fix resource leak

mock_unicon.py changes:
- Removed Cisco proprietary copyright header (lines 5-7), keeping only MPL-2.0
- Fixed resource leak: file opened without context manager now uses 'with' statement

Before:
  states = yaml.safe_load(open(os.path.join(mock_data_dir, file))) or []

After:
  with open(os.path.join(mock_data_dir, file)) as f:
      states = yaml.safe_load(f) or []

* fix(tests): implement proper server startup and shutdown for MockAPIServer

mock_server.py changes:
- Replaced time.sleep(0.5) race condition with proper readiness polling
- Added _wait_for_server_ready() that polls until server responds or timeout
- Implemented proper stop() method using werkzeug.serving.make_server
- Added reset_endpoints() method to clear dynamic endpoints while preserving
  YAML-loaded baseline (enables test isolation with session-scoped fixture)
- Added SERVER_STARTUP_TIMEOUT_SECONDS and SERVER_POLL_INTERVAL_SECONDS constants

This fixes flaky test failures caused by server not being ready, and
prevents port conflicts from improper shutdown.

* fix(tests): add endpoint reset and isolated fixture for test isolation

conftest.py changes:
- Updated mock_api_server fixture to call reset_endpoints() after yield
- Added mock_api_server_isolated fixture (function-scoped) for tests that
  add dynamic endpoints, preventing cross-test pollution

The session-scoped mock_api_server now resets to baseline state between
tests, while mock_api_server_isolated provides per-test isolation.

* fix(tests): use absolute path and fix PEP8 naming in test_pyats_standard

test_pyats_standard.py changes:
- Fixed hardcoded relative path that breaks when run from different directories
  Now uses Path(__file__).parent to construct absolute path to mock_unicon.py
- Renamed classes tc_one -> TcOne, tc_two -> TcTwo (PEP8 CamelCase)
- Fixed decorator spacing: '@ aetest.test' -> '@aetest.test'

* fix(tests): replace debug prints with logging and use monkeypatch

test_integration_pyats.py changes:
- Replaced all print() debug statements with logger.debug() calls
- Moved 'import json' from inside function to module level
- Refactored environment variable handling to use monkeypatch.setenv()
  instead of manual os.environ manipulation with try/finally
- Removed commented-out debug code for static output directories

This improves test maintainability and ensures proper cleanup via
pytest's monkeypatch fixture.

* fix(tests): modernize type hints and use monkeypatch in robot_pabot tests

test_integration_robot_pabot.py changes:
- Changed all tmpdir: str parameters to tmp_path: Path (modern pytest fixture)
- Refactored environment variable handling to use monkeypatch.setenv()
  instead of manual os.environ with try/finally cleanup
- Updated fixture references from tmpdir to tmp_path throughout
- Used Path methods (.exists(), .touch()) instead of os.path equivalents

This improves type safety and ensures proper test isolation via pytest's
automatic cleanup of monkeypatched environment variables.

* fix(tests): replace obfuscated code and emojis in PyATS quicksilver tests

templates_pyats_qs test changes (3 files):
- verify_sdwanmanager_all_sd_wan_edge_configurations_are_in_sync.py
- verify_iosxe_all_sd_wan_control_connections_are_up.py
- verify_aci_apic_appliance_operational_status.py

Changes applied to all:
- Replaced chr(10) with '\n' for clarity
- Replaced emoji markers with text: ❌ -> [FAIL], ✅ -> [PASS]

This prevents encoding issues in CI logs and improves code readability.

* fix(tests): extract f-string join to variable for Python 3.11 compatibility

Python 3.11 does not allow backslash escapes inside f-string expressions.
The previous commit replaced chr(10) with '\n' but left it inside the
f-string expression, causing a SyntaxError.

This fix extracts the join operation to a separate variable before using
it in the f-string:

    failures_text = '\n'.join(failures)
    f"{failures_text}\n\n"

* fix(tests): add proxy bypass for localhost in integration tests

Add session-scoped autouse fixture to ensure 127.0.0.1 is included in
the no_proxy/NO_PROXY environment variables. This prevents the mock API
server requests from being routed through corporate proxies, which was
causing 504 Gateway Timeout errors in environments with proxy configured.

The fixture preserves original proxy settings and restores them after
the test session completes.

* refactor(tests): split robot_pabot tests into focused modules

Split the 493-line test_integration_robot_pabot.py into 4 focused
test modules following Single Responsibility Principle:

- test_cli_basic.py: Basic CLI execution tests (6 tests)
- test_cli_rendering.py: Template rendering tests (8 tests)
- test_cli_ordering.py: Robot test ordering tests (4 tests)
- test_cli_extra_args.py: Extra arguments tests (5 tests)

Improvements:
- Added Google-style docstrings to all 23 test functions
- Renamed generic test names to descriptive names
- Added assertion messages to all assert statements
- Extracted magic number to named constant (ROBOT_ARGUMENT_ERROR_EXIT_CODE)

* add management_ip_variable to test fixture data

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: danischm <danischm@cisco.com>
Co-authored-by: Oliver Boehmer <oli@spine.de>
Co-authored-by: Oliver Boehmer <oboehmer@cisco.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Justyna Chowaniec <79261946+juchowan@users.noreply.github.com>
oboehmer added a commit that referenced this pull request Mar 19, 2026
* Bump pluggy from 1.5.0 to 1.6.0 (#365)

Bumps [pluggy](https://github.com/pytest-dev/pluggy) from 1.5.0 to 1.6.0.
- [Changelog](https://github.com/pytest-dev/pluggy/blob/main/CHANGELOG.rst)
- [Commits](pytest-dev/pluggy@1.5.0...1.6.0)

---
updated-dependencies:
- dependency-name: pluggy
  dependency-version: 1.6.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump click from 8.2.0 to 8.2.1 (#368)

Bumps [click](https://github.com/pallets/click) from 8.2.0 to 8.2.1.
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.rst)
- [Commits](pallets/click@8.2.0...8.2.1)

---
updated-dependencies:
- dependency-name: click
  dependency-version: 8.2.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump typer from 0.15.3 to 0.16.0 (#371)

Bumps [typer](https://github.com/fastapi/typer) from 0.15.3 to 0.16.0.
- [Release notes](https://github.com/fastapi/typer/releases)
- [Changelog](https://github.com/fastapi/typer/blob/master/docs/release-notes.md)
- [Commits](fastapi/typer@0.15.3...0.16.0)

---
updated-dependencies:
- dependency-name: typer
  dependency-version: 0.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump requests from 2.32.3 to 2.32.4 (#372)

Bumps [requests](https://github.com/psf/requests) from 2.32.3 to 2.32.4.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](psf/requests@v2.32.3...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump urllib3 from 2.4.0 to 2.5.0 (#374)

Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](urllib3/urllib3@2.4.0...2.5.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.5.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump rpds-py from 0.24.0 to 0.26.0 (#375)

Bumps [rpds-py](https://github.com/crate-py/rpds) from 0.24.0 to 0.26.0.
- [Release notes](https://github.com/crate-py/rpds/releases)
- [Commits](crate-py/rpds@v0.24.0...v0.26.0)

---
updated-dependencies:
- dependency-name: rpds-py
  dependency-version: 0.26.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump cryptography from 44.0.3 to 45.0.5 (#376)

Bumps [cryptography](https://github.com/pyca/cryptography) from 44.0.3 to 45.0.5.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](pyca/cryptography@44.0.3...45.0.5)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 45.0.5
  dependency-type: indirect
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Migrate to uv

* Refactor error handling

* Various linter updates

* Dependency updates

* Update readme

* Update dependencies and pyproject

* Fix dependency

* Fix robot dependency

* Update versions

* Bump astral-sh/setup-uv from 6 to 7 (#388)

Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6 to 7.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](astral-sh/setup-uv@v6...v7)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* License header updates

* Update changelog

* Update dependabot config for uv

* Bump nac-yaml version

* 1.1.0 version bump

* Bump actions/upload-artifact from 4 to 5 (#391)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix lint workflow for fork prs

* Expose pabot's process option to nac-test cli (#393)

* Increase robot loglevel to debug when verbosity=DEBUG is used (#394)

* Add robotframework-jmespath dependency (#395)

* Update README to include jmespath and add test for 3rd party libs (#396)

* Add support for test case parallelization for capable suites (#390)

* Switch from pabot.main to pabot.main_program and handle exit codes (#400)

Change nac-test to use pabot's main_program() instead of main() to avoid
sys.exit() calls and properly handle exit codes. This allows nac-test to
control the exit behavior and return appropriate exit codes to the caller.

Key changes:
- Update run_pabot() to call pabot.pabot.main_program() instead of main()
- Change run_pabot() return type from None to int
- Return exit code from pabot execution
- Update CLI main() to capture and use exit code
- Remove try/except wrapper in CLI main() - let exceptions propagate
- Disable typer pretty exceptions for cleaner error output

Benefits:
- Proper exit code handling (test failures, errors, etc.)
- No unexpected sys.exit() calls
- Cleaner error messages without verbose typer tracebacks
- Better integration with CI/CD systems

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for passing Robot Framework options to nac-test (#399)

* Add support for passing Robot Framework options to nac-test

Users can now pass additional Robot Framework options directly to
nac-test, which are validated and appended to the pabot invocation.
This enables advanced use cases like custom variables, listeners,
and logging configuration without modifying nac-test's core options.

Key changes:
- Enable extra args in CLI via typer context settings
- Add parse_and_validate_extra_args() to validate Robot Framework options
- Reject pabot-specific options (--processes, --testlevelsplit, etc.)
- Reject datasources/test files in extra arguments
- Return exit code 252 for invalid extra arguments
- Separate pabot_args and robot_args for proper argument ordering
- Add comprehensive unit tests (14 tests covering all scenarios)
- Add type hints and fix all mypy errors
- Update CLI help text to document extra args feature

Implementation details:
- Uses pabot's parse_args() to validate options against Robot Framework
- Filters out datasources and pabot-specific options
- Appends validated args to robot_args before pabot invocation
- Proper error handling with logging and exit codes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Remove pabot.main_program changes from robot-args branch

This commit removes the pabot-specific changes (main_program, exit codes,
exception handling) that belong in the separate pabot-call branch. The
robot-args branch now focuses solely on the extra arguments feature.

Changes:
- Revert run_pabot() return type from int to None
- Use pabot.pabot.main() instead of main_program()
- Remove exit code handling (no return 252)
- Keep try/except in CLI main() for proper error handling
- Update tests to use pabot.pabot.main mock
- Update tests to expect exceptions instead of error codes

The extra args validation and appending logic remains unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Revert "Remove pabot.main_program changes from robot-args branch"

This reverts commit df21b98.

---------

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for chunking templates (#398)

* Update changelog and readms

* Update lock file

* Expand test coverage for chunk split test (#401)

* Fix typo in readme link

* Remove library version numbers from readme

* 1.2.0 version bump

* Support rendering on windows (#404)

* Bump actions/checkout from 5 to 6 (#402)

Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update changelog

* 1.2.1 version bump

* Bump actions/upload-artifact from 5 to 6 (#418)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: resolve all ruff linting errors and warnings

Fix code quality issues identified by ruff to ensure compliance with
project style guidelines and best practices.

Changes:
- Fix syntax error in pabot.py (space in != operator)
- Add missing filecmp import in test_integration.py
- Add proper exception chaining (from e) for B904 violations
- Rename unused loop variables to prefix with underscore (B007)
- Remove trailing whitespace from blank lines (W293)
- Modernize Union type annotations to use | operator (UP007)
- Remove unused Union import after migration to | syntax
- Exclude test fixture directories from ruff checks in pyproject.toml

All ruff checks now pass successfully.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix pabot module import in tests/unit/test_pabot_args.py

* no longer test for RESTinstance robot lib

* add fixture to set bogus ACI_xxx environment for nac-test to pass rendering tests

* add/fix --processes feature

* fix/add ordering_file logic to robot orchestrator

* fix/add passing extra cli args to robot orchestrator

* add integration test for extra args

* update README.md

* fix ruff config changes broken during merge conflict resolution

* fix: resolve all mypy type checking errors

This commit addresses 11 mypy type errors across 4 files:

- connection_utils.py: Add type annotations for dict parameters and
  update function signature to accept None values that are validated
- subprocess_runner.py: Remove unreachable code branch in output
  processing that was flagged due to redundant None check
- connection_broker.py: Add type annotations for testbed attribute,
  AsyncIterator return type, and assertion for loader result
- robot_writer.py: Remove duplicate method definition and add explicit
  type annotation to prevent incorrect type narrowing

All files now pass mypy strict type checking without errors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: restore custom_data handling in render_template for chunked templates

The refactoring that moved data conversion to initialization (for
performance) inadvertently broke the chunked template functionality
by not using the custom_data parameter when provided.

The render_template method now correctly checks if custom_data is
provided (used for chunked templates) and converts it on-demand,
otherwise uses the pre-converted self.template_data.

This fixes the test_nac_test_list_chunked test which was failing
after merging main into the feature branch.

Fixes functionality added in commits 18da546 and ced5983.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* ruff formatting fixes

* fix: add type stub dependencies to pre-commit mypy hook

The pre-commit mypy hook runs in an isolated environment and needs
type stubs explicitly specified via additional_dependencies. Without
these, mypy complains about missing type information for yaml, aiofiles,
and markdown modules.

Added:
- types-PyYAML>=6.0.12.20250822
- types-aiofiles>=24.1.0.20250822
- types-markdown>=3.8.0.20250809

This aligns the pre-commit environment with the project dependencies
and allows mypy to properly type-check imports from these libraries.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: add type annotations to unit test functions

Add proper type annotations to all test functions in tests/unit to
resolve mypy strict type checking errors. Changes include:

- Add -> None return type annotations to all test methods
- Add type annotations for mock parameters (mock_logger,
  mock_connection_class, etc.) using typing.Any
- Add explicit type annotation for connections list variable
- Add type: ignore comment for intentional type mismatch in test

This ensures tests pass mypy strict type checking while maintaining
test clarity and avoiding over-specification of mock types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller tests from shell environment variables

Add autouse fixture to clear all controller-related environment
variables (ACI_*, SDWAN_*, CC_*, MERAKI_*, FMC_*, ISE_*) before
each test in TestCombinedOrchestratorController.

This ensures tests run in a clean environment and results are not
influenced by the caller's shell environment, preventing false
failures when developer has controller credentials set in their
shell.

The fixture uses pytest's monkeypatch to safely remove environment
variables only for the duration of each test.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor: migrate integration test fixture to use monkeypatch

Replace manual environment variable setup/teardown with pytest's
monkeypatch fixture for safer and more robust test isolation.

Benefits of monkeypatch approach:
- Automatic cleanup guaranteed even if test fails
- Safe deletion with raising=False (no KeyError if var missing)
- Preserves and restores original environment variable values
- Less boilerplate code (no yield/try-finally needed)
- Thread-safe state management handled by pytest

The fixture now uses monkeypatch.setenv() which automatically saves
the original value (if any) and restores it after the test, ensuring
the caller's shell environment is never permanently modified.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller detection integration tests from shell environment

Add autouse fixture to clear all controller-related environment
variables before each test in TestControllerDetectionIntegration.

This prevents test failures when developers have controller credentials
set in their shell environment. Without this fix, tests would fail with
"Multiple controller credentials detected" errors when shell variables
conflicted with test-specific environment setup.

The fixture uses pytest's monkeypatch.delenv() with raising=False for
safe deletion that won't fail if a variable doesn't exist.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* add license headers

* add missing test fixture template for extra args test

* security: replace hardcoded /tmp with tempfile.gettempdir() in ConnectionBroker

Fix Bandit B108 vulnerability by using tempfile.gettempdir() instead of
hardcoded /tmp path for output_dir default value. This ensures
cross-platform compatibility and respects system-specific temporary
directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: add usedforsecurity=False to MD5 hash in AuthCache

Fix Bandit B324 vulnerability by explicitly marking MD5 usage as not for
security purposes. The hash is only used to generate cache filenames from
URLs, not for cryptographic security.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp references in emergency dump

Fix Bandit B108 vulnerabilities by:
- Using tempfile.gettempdir() instead of hardcoded /tmp path
- Dynamically checking if file is in temp directory instead of string matching "/tmp/"
- Updated docstrings and log messages to reflect system temp dir usage

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in AUTH_CACHE_DIR constant

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for AUTH_CACHE_DIR.
This ensures cross-platform compatibility and respects system-specific
temporary directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in batching reporter overflow dir

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for default
overflow directory. This ensures cross-platform compatibility while
still allowing override via NAC_TEST_OVERFLOW_DIR environment variable.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: enable Jinja2 autoescape to prevent XSS vulnerabilities

Fix Bandit B701 vulnerability by enabling autoescape for HTML, XML, and
.j2 files using select_autoescape(). This prevents potential XSS attacks
when rendering user-controlled data in HTML reports.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* gitignore bandit-security-report.json created during pipeline run

* Update readme cli help output

* rename robot/pabot integration test file

* Add netconf related packages and update dependencies

* 1.2.2 version bump

* refactor: centralize DEBUG_MODE constant for progressive disclosure

Consolidates the NAC_TEST_DEBUG environment variable check into a single
constant in core/constants.py, eliminating repeated inline checks.

Changes:
- Add DEBUG_MODE constant to nac_test/core/constants.py
- Update cli/main.py to use DEBUG_MODE for pretty_exceptions_enable
- Update combined_orchestrator.py to use DEBUG_MODE for exception handling
- Update batching_reporter.py to use DEBUG_MODE (2 locations)

This enables progressive disclosure: customers get clean error output by
default, while developers can set NAC_TEST_DEBUG=true for full exception
context and verbose tracebacks when debugging.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: danischm <danischm@cisco.com>
Co-authored-by: Oliver Boehmer <oli@spine.de>
Co-authored-by: Oliver Boehmer <oboehmer@cisco.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Justyna Chowaniec <79261946+juchowan@users.noreply.github.com>
oboehmer added a commit that referenced this pull request Mar 19, 2026
* Bump pluggy from 1.5.0 to 1.6.0 (#365)

Bumps [pluggy](https://github.com/pytest-dev/pluggy) from 1.5.0 to 1.6.0.
- [Changelog](https://github.com/pytest-dev/pluggy/blob/main/CHANGELOG.rst)
- [Commits](pytest-dev/pluggy@1.5.0...1.6.0)

---
updated-dependencies:
- dependency-name: pluggy
  dependency-version: 1.6.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump click from 8.2.0 to 8.2.1 (#368)

Bumps [click](https://github.com/pallets/click) from 8.2.0 to 8.2.1.
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.rst)
- [Commits](pallets/click@8.2.0...8.2.1)

---
updated-dependencies:
- dependency-name: click
  dependency-version: 8.2.1
  dependency-type: indirect
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump typer from 0.15.3 to 0.16.0 (#371)

Bumps [typer](https://github.com/fastapi/typer) from 0.15.3 to 0.16.0.
- [Release notes](https://github.com/fastapi/typer/releases)
- [Changelog](https://github.com/fastapi/typer/blob/master/docs/release-notes.md)
- [Commits](fastapi/typer@0.15.3...0.16.0)

---
updated-dependencies:
- dependency-name: typer
  dependency-version: 0.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump requests from 2.32.3 to 2.32.4 (#372)

Bumps [requests](https://github.com/psf/requests) from 2.32.3 to 2.32.4.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](psf/requests@v2.32.3...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump urllib3 from 2.4.0 to 2.5.0 (#374)

Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.4.0 to 2.5.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](urllib3/urllib3@2.4.0...2.5.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.5.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump rpds-py from 0.24.0 to 0.26.0 (#375)

Bumps [rpds-py](https://github.com/crate-py/rpds) from 0.24.0 to 0.26.0.
- [Release notes](https://github.com/crate-py/rpds/releases)
- [Commits](crate-py/rpds@v0.24.0...v0.26.0)

---
updated-dependencies:
- dependency-name: rpds-py
  dependency-version: 0.26.0
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump cryptography from 44.0.3 to 45.0.5 (#376)

Bumps [cryptography](https://github.com/pyca/cryptography) from 44.0.3 to 45.0.5.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](pyca/cryptography@44.0.3...45.0.5)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 45.0.5
  dependency-type: indirect
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Migrate to uv

* Refactor error handling

* Various linter updates

* Dependency updates

* Update readme

* Update dependencies and pyproject

* Fix dependency

* Fix robot dependency

* Update versions

* Bump astral-sh/setup-uv from 6 to 7 (#388)

Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6 to 7.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](astral-sh/setup-uv@v6...v7)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* License header updates

* Update changelog

* Update dependabot config for uv

* Bump nac-yaml version

* 1.1.0 version bump

* Bump actions/upload-artifact from 4 to 5 (#391)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Fix lint workflow for fork prs

* Expose pabot's process option to nac-test cli (#393)

* Increase robot loglevel to debug when verbosity=DEBUG is used (#394)

* Add robotframework-jmespath dependency (#395)

* Update README to include jmespath and add test for 3rd party libs (#396)

* Add support for test case parallelization for capable suites (#390)

* Switch from pabot.main to pabot.main_program and handle exit codes (#400)

Change nac-test to use pabot's main_program() instead of main() to avoid
sys.exit() calls and properly handle exit codes. This allows nac-test to
control the exit behavior and return appropriate exit codes to the caller.

Key changes:
- Update run_pabot() to call pabot.pabot.main_program() instead of main()
- Change run_pabot() return type from None to int
- Return exit code from pabot execution
- Update CLI main() to capture and use exit code
- Remove try/except wrapper in CLI main() - let exceptions propagate
- Disable typer pretty exceptions for cleaner error output

Benefits:
- Proper exit code handling (test failures, errors, etc.)
- No unexpected sys.exit() calls
- Cleaner error messages without verbose typer tracebacks
- Better integration with CI/CD systems

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for passing Robot Framework options to nac-test (#399)

* Add support for passing Robot Framework options to nac-test

Users can now pass additional Robot Framework options directly to
nac-test, which are validated and appended to the pabot invocation.
This enables advanced use cases like custom variables, listeners,
and logging configuration without modifying nac-test's core options.

Key changes:
- Enable extra args in CLI via typer context settings
- Add parse_and_validate_extra_args() to validate Robot Framework options
- Reject pabot-specific options (--processes, --testlevelsplit, etc.)
- Reject datasources/test files in extra arguments
- Return exit code 252 for invalid extra arguments
- Separate pabot_args and robot_args for proper argument ordering
- Add comprehensive unit tests (14 tests covering all scenarios)
- Add type hints and fix all mypy errors
- Update CLI help text to document extra args feature

Implementation details:
- Uses pabot's parse_args() to validate options against Robot Framework
- Filters out datasources and pabot-specific options
- Appends validated args to robot_args before pabot invocation
- Proper error handling with logging and exit codes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Remove pabot.main_program changes from robot-args branch

This commit removes the pabot-specific changes (main_program, exit codes,
exception handling) that belong in the separate pabot-call branch. The
robot-args branch now focuses solely on the extra arguments feature.

Changes:
- Revert run_pabot() return type from int to None
- Use pabot.pabot.main() instead of main_program()
- Remove exit code handling (no return 252)
- Keep try/except in CLI main() for proper error handling
- Update tests to use pabot.pabot.main mock
- Update tests to expect exceptions instead of error codes

The extra args validation and appending logic remains unchanged.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Revert "Remove pabot.main_program changes from robot-args branch"

This reverts commit df21b98.

---------

Co-authored-by: Claude <noreply@anthropic.com>

* Add support for chunking templates (#398)

* Update changelog and readms

* Update lock file

* Expand test coverage for chunk split test (#401)

* Fix typo in readme link

* Remove library version numbers from readme

* 1.2.0 version bump

* feat(path_setup): auto-discover pyats_common for test imports

Add find_pyats_common_parent() to search test directory tree for
pyats_common subdirectory and add its parent to PYTHONPATH. This
enables test files to use simple imports like:
  from pyats_common.apic_base_test import APICTestBase

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* add verbose option to pyats when running at DEBUG level, log pyats output as well when in DEBUG

* current state, not yet working

* add simple test for pipeline - WIP

* add integration tests and support for mock devices

* use easypy.run to invoke script

* do not assume a default CONTROLLER_TYPE

* remove assumption for CONTROLLER_TYPE being ACI in base_test too

* adjust test

* add some debug log statements

* add warning about potential issues with python3.11 on macOS

* connect using log_stdout=False

* fix simple test, and ruff formatting

* simple test changes, WIP

* Support rendering on windows (#404)

* Bump actions/checkout from 5 to 6 (#402)

Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update changelog

* 1.2.1 version bump

* update with mock flask server - WIP

* remove debug logs

* add mock-server to perform API testing in integration tests

* add integration tests for quicksilver-generated templates

* add type hints

* Bump actions/upload-artifact from 5 to 6 (#418)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* add sdwan mock api results

* adjust mock-server file, create mock-server test

* fix: resolve all ruff linting errors and warnings

Fix code quality issues identified by ruff to ensure compliance with
project style guidelines and best practices.

Changes:
- Fix syntax error in pabot.py (space in != operator)
- Add missing filecmp import in test_integration.py
- Add proper exception chaining (from e) for B904 violations
- Rename unused loop variables to prefix with underscore (B007)
- Remove trailing whitespace from blank lines (W293)
- Modernize Union type annotations to use | operator (UP007)
- Remove unused Union import after migration to | syntax
- Exclude test fixture directories from ruff checks in pyproject.toml

All ruff checks now pass successfully.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix pabot module import in tests/unit/test_pabot_args.py

* no longer test for RESTinstance robot lib

* add fixture to set bogus ACI_xxx environment for nac-test to pass rendering tests

* add/fix --processes feature

* fix/add ordering_file logic to robot orchestrator

* fix/add passing extra cli args to robot orchestrator

* add integration test for extra args

* update README.md

* fix ruff config changes broken during merge conflict resolution

* fix: resolve all mypy type checking errors

This commit addresses 11 mypy type errors across 4 files:

- connection_utils.py: Add type annotations for dict parameters and
  update function signature to accept None values that are validated
- subprocess_runner.py: Remove unreachable code branch in output
  processing that was flagged due to redundant None check
- connection_broker.py: Add type annotations for testbed attribute,
  AsyncIterator return type, and assertion for loader result
- robot_writer.py: Remove duplicate method definition and add explicit
  type annotation to prevent incorrect type narrowing

All files now pass mypy strict type checking without errors.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: restore custom_data handling in render_template for chunked templates

The refactoring that moved data conversion to initialization (for
performance) inadvertently broke the chunked template functionality
by not using the custom_data parameter when provided.

The render_template method now correctly checks if custom_data is
provided (used for chunked templates) and converts it on-demand,
otherwise uses the pre-converted self.template_data.

This fixes the test_nac_test_list_chunked test which was failing
after merging main into the feature branch.

Fixes functionality added in commits 18da546 and ced5983.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* ruff formatting fixes

* fix: add type stub dependencies to pre-commit mypy hook

The pre-commit mypy hook runs in an isolated environment and needs
type stubs explicitly specified via additional_dependencies. Without
these, mypy complains about missing type information for yaml, aiofiles,
and markdown modules.

Added:
- types-PyYAML>=6.0.12.20250822
- types-aiofiles>=24.1.0.20250822
- types-markdown>=3.8.0.20250809

This aligns the pre-commit environment with the project dependencies
and allows mypy to properly type-check imports from these libraries.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: add type annotations to unit test functions

Add proper type annotations to all test functions in tests/unit to
resolve mypy strict type checking errors. Changes include:

- Add -> None return type annotations to all test methods
- Add type annotations for mock parameters (mock_logger,
  mock_connection_class, etc.) using typing.Any
- Add explicit type annotation for connections list variable
- Add type: ignore comment for intentional type mismatch in test

This ensures tests pass mypy strict type checking while maintaining
test clarity and avoiding over-specification of mock types.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller tests from shell environment variables

Add autouse fixture to clear all controller-related environment
variables (ACI_*, SDWAN_*, CC_*, MERAKI_*, FMC_*, ISE_*) before
each test in TestCombinedOrchestratorController.

This ensures tests run in a clean environment and results are not
influenced by the caller's shell environment, preventing false
failures when developer has controller credentials set in their
shell.

The fixture uses pytest's monkeypatch to safely remove environment
variables only for the duration of each test.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor: migrate integration test fixture to use monkeypatch

Replace manual environment variable setup/teardown with pytest's
monkeypatch fixture for safer and more robust test isolation.

Benefits of monkeypatch approach:
- Automatic cleanup guaranteed even if test fails
- Safe deletion with raising=False (no KeyError if var missing)
- Preserves and restores original environment variable values
- Less boilerplate code (no yield/try-finally needed)
- Thread-safe state management handled by pytest

The fixture now uses monkeypatch.setenv() which automatically saves
the original value (if any) and restores it after the test, ensuring
the caller's shell environment is never permanently modified.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: isolate controller detection integration tests from shell environment

Add autouse fixture to clear all controller-related environment
variables before each test in TestControllerDetectionIntegration.

This prevents test failures when developers have controller credentials
set in their shell environment. Without this fix, tests would fail with
"Multiple controller credentials detected" errors when shell variables
conflicted with test-specific environment setup.

The fixture uses pytest's monkeypatch.delenv() with raising=False for
safe deletion that won't fail if a variable doesn't exist.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* add license headers

* add missing test fixture template for extra args test

* security: replace hardcoded /tmp with tempfile.gettempdir() in ConnectionBroker

Fix Bandit B108 vulnerability by using tempfile.gettempdir() instead of
hardcoded /tmp path for output_dir default value. This ensures
cross-platform compatibility and respects system-specific temporary
directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: add usedforsecurity=False to MD5 hash in AuthCache

Fix Bandit B324 vulnerability by explicitly marking MD5 usage as not for
security purposes. The hash is only used to generate cache filenames from
URLs, not for cryptographic security.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp references in emergency dump

Fix Bandit B108 vulnerabilities by:
- Using tempfile.gettempdir() instead of hardcoded /tmp path
- Dynamically checking if file is in temp directory instead of string matching "/tmp/"
- Updated docstrings and log messages to reflect system temp dir usage

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in AUTH_CACHE_DIR constant

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for AUTH_CACHE_DIR.
This ensures cross-platform compatibility and respects system-specific
temporary directory configurations.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: replace hardcoded /tmp in batching reporter overflow dir

Fix Bandit B108 vulnerability by using os.path.join with
tempfile.gettempdir() instead of hardcoded /tmp path for default
overflow directory. This ensures cross-platform compatibility while
still allowing override via NAC_TEST_OVERFLOW_DIR environment variable.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* security: enable Jinja2 autoescape to prevent XSS vulnerabilities

Fix Bandit B701 vulnerability by enabling autoescape for HTML, XML, and
.j2 files using select_autoescape(). This prevents potential XSS attacks
when rendering user-controlled data in HTML reports.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* gitignore bandit-security-report.json created during pipeline run

* Update readme cli help output

* rename robot/pabot integration test file

* Add netconf related packages and update dependencies

* 1.2.2 version bump

* adjust and fix aci integration tests

* remove environment vars after testing

* fix license check

* remove unfinished tests

* use tmpdir

* add debugging for CI troubleshooting

* attempt to fix event loop issue in CI

* add more debug code to troubleshoot CI failure

* add missing nac-test-pyats-common  to CI pipeline

* sum up passed/failed for check (in case we have multiple results.json files)

* re-organize test case fixture directories

use a common base dir, and then add specific archs as subdirectories to avoid directory bloat in fixture directory

* Fix Python 3.12 asyncio compatibility with get_or_create_event_loop

Python 3.12 changed asyncio.get_event_loop() behavior to raise
RuntimeError when called from the main thread without an active event loop,
breaking async operations that run synchronous PyATS/Unicon calls via
loop.run_in_executor().

Previous behavior (Python 3.10-3.11):
- asyncio.get_event_loop() automatically created a new event loop if none existed

New behavior (Python 3.12+):
- asyncio.get_event_loop() raises RuntimeError if no event loop exists
- Must explicitly call asyncio.new_event_loop() and set_event_loop()

Solution:
Created get_or_create_event_loop() helper that handles both behaviors:
- Tries to get existing event loop
- If closed or RuntimeError, creates and sets a new loop
- Works across Python 3.10-3.12+

Replaced 9 instances of asyncio.get_event_loop() across 4 modules:
- nac_test/pyats_core/broker/connection_broker.py (3 calls)
- nac_test/pyats_core/common/ssh_base_test.py (3 calls)
- nac_test/pyats_core/ssh/connection_manager.py (2 calls)
- nac_test/pyats_core/reporting/multi_archive_generator.py (1 call)

These calls are used to run blocking Unicon operations (connect, disconnect,
execute) in thread pools via run_in_executor() to prevent blocking the
async event loop.

* add sdwan integration tests (both api and d2d)

* add license header

* test: remove test_mock_server.py - tests mock infrastructure, not business logic

These tests only verify that the MockAPIServer returns what it was
configured to return:
- test_mock_api_server_endpoint_matching: configures endpoints, asserts they return configured data
- test_nac_test_with_mock_api_complex_urls: same pattern with complex URLs
- test_nac_test_with_mock_api_dynamic: adds endpoint with response X, asserts response is X

This violates the principle: "What MUST NEVER be Tested: whether mocks
return what you told them to return."

The mock server is infrastructure to enable testing real business logic,
not something that needs its own test coverage.

* test: remove test_controller_detection_consistency - tests Python determinism

This test calls detect_controller_type() three times with identical
environment and asserts all results are equal. This tests whether Python
functions return consistent results when called with the same inputs -
which is testing Python's deterministic execution, not business logic.

A pure function will always return the same result for the same inputs.
Testing this adds no value unless there's caching or stateful behavior
that could cause inconsistency (there isn't).

Violates: "What MUST NEVER be Tested: Whether Python's standard library works"

* test: remove mock assertion from test_end_to_end_controller_detection

Removed the pattern that mocks EnvironmentValidator and asserts it was
called with the correct argument:

    with patch("...EnvironmentValidator") as mock_validator:
        orchestrator.validate_environment()
        mock_validator.validate_controller_env.assert_called_once_with("SDWAN")

This tests whether validate_environment() calls EnvironmentValidator with
the right argument - essentially testing "whether one-line wrapper functions
call the functions they wrap."

The real test is already done: assert orchestrator.controller_type == "SDWAN"
which validates the business logic (controller was correctly detected).

Violates: "What MUST NEVER be Tested: whether one-line wrapper functions
call the functions they wrap"

* fix(tests): remove conflicting copyright header and fix resource leak

mock_unicon.py changes:
- Removed Cisco proprietary copyright header (lines 5-7), keeping only MPL-2.0
- Fixed resource leak: file opened without context manager now uses 'with' statement

Before:
  states = yaml.safe_load(open(os.path.join(mock_data_dir, file))) or []

After:
  with open(os.path.join(mock_data_dir, file)) as f:
      states = yaml.safe_load(f) or []

* fix(tests): implement proper server startup and shutdown for MockAPIServer

mock_server.py changes:
- Replaced time.sleep(0.5) race condition with proper readiness polling
- Added _wait_for_server_ready() that polls until server responds or timeout
- Implemented proper stop() method using werkzeug.serving.make_server
- Added reset_endpoints() method to clear dynamic endpoints while preserving
  YAML-loaded baseline (enables test isolation with session-scoped fixture)
- Added SERVER_STARTUP_TIMEOUT_SECONDS and SERVER_POLL_INTERVAL_SECONDS constants

This fixes flaky test failures caused by server not being ready, and
prevents port conflicts from improper shutdown.

* fix(tests): add endpoint reset and isolated fixture for test isolation

conftest.py changes:
- Updated mock_api_server fixture to call reset_endpoints() after yield
- Added mock_api_server_isolated fixture (function-scoped) for tests that
  add dynamic endpoints, preventing cross-test pollution

The session-scoped mock_api_server now resets to baseline state between
tests, while mock_api_server_isolated provides per-test isolation.

* fix(tests): use absolute path and fix PEP8 naming in test_pyats_standard

test_pyats_standard.py changes:
- Fixed hardcoded relative path that breaks when run from different directories
  Now uses Path(__file__).parent to construct absolute path to mock_unicon.py
- Renamed classes tc_one -> TcOne, tc_two -> TcTwo (PEP8 CamelCase)
- Fixed decorator spacing: '@ aetest.test' -> '@aetest.test'

* fix(tests): replace debug prints with logging and use monkeypatch

test_integration_pyats.py changes:
- Replaced all print() debug statements with logger.debug() calls
- Moved 'import json' from inside function to module level
- Refactored environment variable handling to use monkeypatch.setenv()
  instead of manual os.environ manipulation with try/finally
- Removed commented-out debug code for static output directories

This improves test maintainability and ensures proper cleanup via
pytest's monkeypatch fixture.

* fix(tests): modernize type hints and use monkeypatch in robot_pabot tests

test_integration_robot_pabot.py changes:
- Changed all tmpdir: str parameters to tmp_path: Path (modern pytest fixture)
- Refactored environment variable handling to use monkeypatch.setenv()
  instead of manual os.environ with try/finally cleanup
- Updated fixture references from tmpdir to tmp_path throughout
- Used Path methods (.exists(), .touch()) instead of os.path equivalents

This improves type safety and ensures proper test isolation via pytest's
automatic cleanup of monkeypatched environment variables.

* fix(tests): replace obfuscated code and emojis in PyATS quicksilver tests

templates_pyats_qs test changes (3 files):
- verify_sdwanmanager_all_sd_wan_edge_configurations_are_in_sync.py
- verify_iosxe_all_sd_wan_control_connections_are_up.py
- verify_aci_apic_appliance_operational_status.py

Changes applied to all:
- Replaced chr(10) with '\n' for clarity
- Replaced emoji markers with text: ❌ -> [FAIL], ✅ -> [PASS]

This prevents encoding issues in CI logs and improves code readability.

* fix(tests): extract f-string join to variable for Python 3.11 compatibility

Python 3.11 does not allow backslash escapes inside f-string expressions.
The previous commit replaced chr(10) with '\n' but left it inside the
f-string expression, causing a SyntaxError.

This fix extracts the join operation to a separate variable before using
it in the f-string:

    failures_text = '\n'.join(failures)
    f"{failures_text}\n\n"

* fix(tests): add proxy bypass for localhost in integration tests

Add session-scoped autouse fixture to ensure 127.0.0.1 is included in
the no_proxy/NO_PROXY environment variables. This prevents the mock API
server requests from being routed through corporate proxies, which was
causing 504 Gateway Timeout errors in environments with proxy configured.

The fixture preserves original proxy settings and restores them after
the test session completes.

* refactor(tests): split robot_pabot tests into focused modules

Split the 493-line test_integration_robot_pabot.py into 4 focused
test modules following Single Responsibility Principle:

- test_cli_basic.py: Basic CLI execution tests (6 tests)
- test_cli_rendering.py: Template rendering tests (8 tests)
- test_cli_ordering.py: Robot test ordering tests (4 tests)
- test_cli_extra_args.py: Extra arguments tests (5 tests)

Improvements:
- Added Google-style docstrings to all 23 test functions
- Renamed generic test names to descriptive names
- Added assertion messages to all assert statements
- Extracted magic number to named constant (ROBOT_ARGUMENT_ERROR_EXIT_CODE)

* add management_ip_variable to test fixture data

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: danischm <danischm@cisco.com>
Co-authored-by: Oliver Boehmer <oli@spine.de>
Co-authored-by: Oliver Boehmer <oboehmer@cisco.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Justyna Chowaniec <79261946+juchowan@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file python Pull requests that update Python code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant