netbox-super-cli 1.7.0__tar.gz → 1.8.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/bench.yml +2 -2
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/claude.yml +2 -2
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/docs.yml +4 -4
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/e2e.yml +37 -2
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/lint.yml +6 -6
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/release.yml +3 -3
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/test.yml +2 -2
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.pre-commit-config.yaml +1 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/AGENTS.md +1 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/CHANGELOG.md +109 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/CLAUDE.md +1 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/PKG-INFO +22 -1
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/README.md +20 -0
- netbox_super_cli-1.8.1/SECURITY.md +12 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/architecture/http-client.md +9 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/architecture/overview.md +1 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/getting-started/concepts.md +16 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/getting-started/first-run.md +6 -2
- netbox_super_cli-1.8.1/docs/guides/branching.md +140 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/ci-and-automation.md +17 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/interactive-tui.md +16 -0
- netbox_super_cli-1.8.1/docs/guides/keyring.md +86 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/managing-profiles.md +29 -6
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/output-formats.md +5 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/using-with-ai-agents.md +1 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/working-with-plugins.md +11 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/writes-and-safety.md +17 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/index.md +3 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/reference/config.md +2 -1
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/justfile +10 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/mkdocs.yml +2 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/_version.py +1 -1
- netbox_super_cli-1.8.1/nsc/auth/keyring_store.py +77 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/auth/verify.py +71 -25
- netbox_super_cli-1.8.1/nsc/branching/__init__.py +5 -0
- netbox_super_cli-1.8.1/nsc/branching/api.py +100 -0
- netbox_super_cli-1.8.1/nsc/branching/errors.py +82 -0
- netbox_super_cli-1.8.1/nsc/branching/jobs.py +57 -0
- netbox_super_cli-1.8.1/nsc/branching/models.py +42 -0
- netbox_super_cli-1.8.1/nsc/branching/resolve.py +46 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/aliases_commands.py +4 -3
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/app.py +49 -3
- netbox_super_cli-1.8.1/nsc/cli/branch_commands.py +460 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/cache_commands.py +4 -2
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/globals.py +15 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/handlers.py +23 -9
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/login_commands.py +153 -25
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/profiles_commands.py +2 -2
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/registration.py +12 -5
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/runtime.py +105 -8
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/tui_commands.py +19 -1
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/config/loader.py +11 -1
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/config/models.py +31 -2
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/config/writer.py +6 -1
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/http/client.py +48 -28
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/http/errors.py +4 -0
- netbox_super_cli-1.8.1/nsc/http/pagination.py +78 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/__init__.py +2 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/app.py +6 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/keymap.py +1 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/list.py +104 -7
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/styles.tcss +6 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/view.py +11 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/pyproject.toml +4 -1
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/skills/netbox-super-cli/SKILL.md +31 -1
- netbox_super_cli-1.8.1/tests/auth/test_keyring_store.py +58 -0
- netbox_super_cli-1.8.1/tests/auth/test_verify.py +283 -0
- netbox_super_cli-1.8.1/tests/branching/_fixtures.py +54 -0
- netbox_super_cli-1.8.1/tests/branching/test_api.py +159 -0
- netbox_super_cli-1.8.1/tests/branching/test_jobs.py +70 -0
- netbox_super_cli-1.8.1/tests/branching/test_resolve.py +106 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_aliases_commands.py +15 -0
- netbox_super_cli-1.8.1/tests/cli/test_branch_commands.py +291 -0
- netbox_super_cli-1.8.1/tests/cli/test_branch_lifecycle.py +179 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_cache_commands.py +31 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_handlers.py +72 -0
- netbox_super_cli-1.8.1/tests/cli/test_lazy_keyring_import.py +27 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_login_commands.py +26 -0
- netbox_super_cli-1.8.1/tests/cli/test_login_keyring.py +528 -0
- netbox_super_cli-1.8.1/tests/cli/test_runtime_branch.py +157 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_tui_command.py +2 -0
- netbox_super_cli-1.8.1/tests/config/test_keyring_tag.py +67 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_models.py +6 -0
- netbox_super_cli-1.8.1/tests/conftest.py +85 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/README.md +12 -0
- netbox_super_cli-1.8.1/tests/e2e/branching/Dockerfile +5 -0
- netbox_super_cli-1.8.1/tests/e2e/branching/plugins.py +21 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/conftest.py +8 -0
- netbox_super_cli-1.8.1/tests/e2e/docker-compose.branching.yml +45 -0
- netbox_super_cli-1.8.1/tests/e2e/test_branching.py +137 -0
- netbox_super_cli-1.8.1/tests/e2e/test_keyring_roundtrip.py +79 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_login.py +53 -2
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_client.py +53 -0
- netbox_super_cli-1.8.1/tests/http/test_client_branch.py +112 -0
- netbox_super_cli-1.8.1/tests/http/test_pagination.py +127 -0
- netbox_super_cli-1.8.1/tests/tui/__init__.py +0 -0
- netbox_super_cli-1.8.1/tests/tui/test_branch_indicator.py +24 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_list_screen.py +298 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_view.py +17 -1
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/uv.lock +234 -23
- netbox_super_cli-1.7.0/tests/auth/test_verify.py +0 -70
- netbox_super_cli-1.7.0/tests/conftest.py +0 -41
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/ISSUE_TEMPLATE/docs.yml +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/dependabot.yml +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/pull_request_template.md +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.github/workflows/skill-convention-review.yml +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.gitignore +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/.python-version +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/LICENSE +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/architecture/caching.md +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/architecture/command-generation.md +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/architecture/schema-loading.md +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/assets/tui/detail.svg +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/assets/tui/filter.svg +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/assets/tui/list.svg +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/assets/tui/picker.svg +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/assets/tui/search.svg +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/contributing/adding-bundled-schemas.md +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/contributing/branching.md +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/contributing/development.md +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/contributing/release-process.md +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/getting-started/install.md +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/guides/audit-log.md +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/reference/cli.md +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/reference/exit-codes.md +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/docs/reference/schemas.md +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/__main__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/aliases/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/aliases/resolver.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/auth/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/builder/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/builder/build.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cache/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cache/store.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/commands_dump.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/config_commands.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/init_commands.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/skill_commands.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/apply.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/bulk.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/coercion.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/confirmation.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/input.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/cli/writes/preflight.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/completion/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/completion/cache_probe.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/completion/callbacks.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/completion/providers.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/config/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/config/saved_searches.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/config/settings.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/http/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/http/audit.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/http/retry.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/model/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/model/command_model.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/_console.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/colors.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/csv_.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/errors.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/explain.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/flatten.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/headers.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/json_.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/jsonl.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/render.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/table.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/output/yaml_.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/savedfilters/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/savedfilters/custom_fields.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/savedfilters/objecttypes.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/savedfilters/params.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/savedfilters/store.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/savedfilters/tags.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schema/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schema/hashing.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schema/loader.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schema/models.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schema/source.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schemas/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schemas/bundled/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schemas/bundled/manifest.yaml +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schemas/bundled/netbox-4.5.10.json.gz +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/schemas/bundled/netbox-4.6.0.json.gz +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/skill/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/_bindings.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/bulk.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/catalog.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/columns.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/errors.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/filters.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/fk.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/forms.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/nav.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/relations.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/bulk_edit_form.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/columns.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/detail.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/edit_form.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/filter.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/global_search.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/picker.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/record_picker.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/screens/saved_search_picker.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/search.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/selection.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/_modal.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/bulk_diff.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/bulk_summary.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/confirm.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/diff.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/help.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/nsc/tui/widgets/nav_tree.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/scripts/gen_docs.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/scripts/sync_agents_md.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/aliases/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/aliases/test_resolver.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/audit/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/audit/test_redaction_full.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/auth/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/benchmarks/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/benchmarks/test_startup.py +0 -0
- {netbox_super_cli-1.7.0/tests/builder → netbox_super_cli-1.8.1/tests/branching}/__init__.py +0 -0
- {netbox_super_cli-1.7.0/tests/cache → netbox_super_cli-1.8.1/tests/builder}/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/builder/test_build.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/builder/test_default_columns.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/builder/test_fk_metadata.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/builder/test_redaction_marking.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/builder/test_request_body_shape.py +0 -0
- {netbox_super_cli-1.7.0/tests/cli → netbox_super_cli-1.8.1/tests/cache}/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cache/test_prune.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cache/test_store.py +0 -0
- {netbox_super_cli-1.7.0/tests/cli/writes → netbox_super_cli-1.8.1/tests/cli}/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_app_smoke.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_commands_dump.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_completion_protocol_smoke.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_completion_smoke.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_config_commands.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_dynamic_completion.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_explain.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_globals_color.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_init_commands.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_lazy_httpx2_import.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_lazy_textual_import.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_meta_subcommands_under_broken_config.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_ndjson_input.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_profiles_commands.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_registration.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_respx_integration.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_runtime.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_runtime_color.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_skill_commands.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_stdin_sniffer.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/test_writes_respx.py +0 -0
- {netbox_super_cli-1.7.0/tests/config → netbox_super_cli-1.8.1/tests/cli/writes}/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_apply.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_bulk.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_confirmation.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_handler_helpers.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_handlers_audit.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_input.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/cli/writes/test_preflight.py +0 -0
- {netbox_super_cli-1.7.0/tests/http → netbox_super_cli-1.8.1/tests/config}/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_loader.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_saved_search_fallback.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_saved_searches.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_settings_private_dir.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_writer_atomicity.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_writer_dotted_paths.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/config/test_writer_roundtrip.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/docker-compose.yml +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_audit_redaction.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_auth_error_envelope.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_bulk_create_with_loop_fallback.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_full_cycle.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_ndjson.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_preflight_blocks_apply.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/test_validation_error_envelope_from_netbox.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/e2e/wait_for_netbox.sh +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/fixtures/profiles/single_profile.yaml +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/fixtures/responses/auth_401.json +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/fixtures/responses/circuits_providers_list.json +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/fixtures/responses/dcim_devices_get.json +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/fixtures/responses/dcim_devices_list_p1.json +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/fixtures/responses/dcim_devices_list_p2.json +0 -0
- {netbox_super_cli-1.7.0/tests/model → netbox_super_cli-1.8.1/tests/http}/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_audit.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_audit_permissions.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_audit_redaction.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_client_redaction_threading.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_errors.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/http/test_retry.py +0 -0
- {netbox_super_cli-1.7.0/tests/output → netbox_super_cli-1.8.1/tests/model}/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/model/test_command_model.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/model/test_request_body_shape.py +0 -0
- {netbox_super_cli-1.7.0/tests/savedfilters → netbox_super_cli-1.8.1/tests/output}/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_colors.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_console.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_csv.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_errors.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_errors_aliases.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_errors_color.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_explain.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_explain_color.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_flatten.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_input_error_envelope.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_json.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_jsonl.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_render_dispatch.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_table.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_table_color.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/output/test_yaml.py +0 -0
- {netbox_super_cli-1.7.0/tests/schema → netbox_super_cli-1.8.1/tests/savedfilters}/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/savedfilters/test_custom_fields.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/savedfilters/test_objecttypes.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/savedfilters/test_params.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/savedfilters/test_store.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/savedfilters/test_tags.py +0 -0
- {netbox_super_cli-1.7.0/tests/scripts → netbox_super_cli-1.8.1/tests/schema}/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/schema/test_hashing.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/schema/test_loader.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/schema/test_models.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/schema/test_source.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/schema/test_source_ttl.py +0 -0
- {netbox_super_cli-1.7.0/tests/skill → netbox_super_cli-1.8.1/tests/scripts}/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/scripts/test_gen_docs.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/scripts/test_sync_agents_md.py +0 -0
- {netbox_super_cli-1.7.0/tests/tui → netbox_super_cli-1.8.1/tests/skill}/__init__.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/skill/test_bundle.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/test_packaging.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_app.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bindings.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bulk_apply.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bulk_diff.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bulk_diff_modal.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bulk_edit_form.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bulk_import_isolation.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_bulk_summary.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_catalog.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_column_chooser.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_columns.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_detail_screen.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_diff.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_diff_modal.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_edit_form.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_errors.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_filter_screen.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_filters.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_fk_resolve.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_forms.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_global_search.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_help_overlay.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_keymap.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_picker.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_record_picker.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_relations.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_saved_filter_integration.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_search.py +0 -0
- {netbox_super_cli-1.7.0 → netbox_super_cli-1.8.1}/tests/tui/test_selection.py +0 -0
|
@@ -13,8 +13,8 @@ jobs:
|
|
|
13
13
|
startup-time:
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
15
|
steps:
|
|
16
|
-
- uses: actions/checkout@v7
|
|
17
|
-
- uses: astral-sh/setup-uv@
|
|
16
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
17
|
+
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
18
18
|
- name: Install
|
|
19
19
|
run: uv sync --all-extras --dev
|
|
20
20
|
- name: Benchmark
|
|
@@ -41,13 +41,13 @@ jobs:
|
|
|
41
41
|
actions: read # Required for Claude to read CI results on PRs
|
|
42
42
|
steps:
|
|
43
43
|
- name: Checkout repository
|
|
44
|
-
uses: actions/checkout@v7
|
|
44
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
45
45
|
with:
|
|
46
46
|
fetch-depth: 1
|
|
47
47
|
|
|
48
48
|
- name: Run Claude Code
|
|
49
49
|
id: claude
|
|
50
|
-
uses: anthropics/claude-code-action@v1
|
|
50
|
+
uses: anthropics/claude-code-action@db77d4d3c98f3f6380e7cd45ffba2342a3dbde3c # v1
|
|
51
51
|
with:
|
|
52
52
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
53
53
|
|
|
@@ -26,9 +26,9 @@ jobs:
|
|
|
26
26
|
build:
|
|
27
27
|
runs-on: ubuntu-latest
|
|
28
28
|
steps:
|
|
29
|
-
- uses: actions/checkout@v7
|
|
29
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
30
30
|
- name: Install uv
|
|
31
|
-
uses: astral-sh/setup-uv@
|
|
31
|
+
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
32
32
|
with:
|
|
33
33
|
enable-cache: true
|
|
34
34
|
- name: Install Python
|
|
@@ -39,7 +39,7 @@ jobs:
|
|
|
39
39
|
run: uv run zensical build --strict
|
|
40
40
|
- name: Upload Pages artifact
|
|
41
41
|
if: github.ref_type == 'tag'
|
|
42
|
-
uses: actions/upload-pages-artifact@v5
|
|
42
|
+
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5
|
|
43
43
|
with:
|
|
44
44
|
path: site
|
|
45
45
|
|
|
@@ -52,4 +52,4 @@ jobs:
|
|
|
52
52
|
url: ${{ steps.deployment.outputs.page_url }}
|
|
53
53
|
steps:
|
|
54
54
|
- id: deployment
|
|
55
|
-
uses: actions/deploy-pages@v5
|
|
55
|
+
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5
|
|
@@ -6,6 +6,11 @@ on:
|
|
|
6
6
|
pull_request:
|
|
7
7
|
paths:
|
|
8
8
|
- 'nsc/http/**'
|
|
9
|
+
- 'nsc/branching/**'
|
|
10
|
+
- 'nsc/cli/branch_commands.py'
|
|
11
|
+
- 'nsc/auth/**'
|
|
12
|
+
- 'nsc/cli/login_commands.py'
|
|
13
|
+
- 'nsc/cli/profiles_commands.py'
|
|
9
14
|
- 'nsc/cli/handlers.py'
|
|
10
15
|
- 'nsc/cli/registration.py'
|
|
11
16
|
- 'nsc/cli/writes/**'
|
|
@@ -34,8 +39,8 @@ jobs:
|
|
|
34
39
|
env:
|
|
35
40
|
NETBOX_IMAGE: netboxcommunity/netbox:${{ matrix.netbox-version }}
|
|
36
41
|
steps:
|
|
37
|
-
- uses: actions/checkout@v7
|
|
38
|
-
- uses: astral-sh/setup-uv@
|
|
42
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
43
|
+
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
39
44
|
- name: Sync deps
|
|
40
45
|
run: uv sync --frozen
|
|
41
46
|
- name: Start NetBox
|
|
@@ -54,3 +59,33 @@ jobs:
|
|
|
54
59
|
- name: Stop NetBox
|
|
55
60
|
if: always()
|
|
56
61
|
run: docker compose -f tests/e2e/docker-compose.yml down -v
|
|
62
|
+
|
|
63
|
+
e2e-branching:
|
|
64
|
+
name: e2e-branching (v4.7.3 + branching 1.2.2)
|
|
65
|
+
runs-on: ubuntu-latest
|
|
66
|
+
timeout-minutes: 20
|
|
67
|
+
env:
|
|
68
|
+
NETBOX_IMAGE: netboxcommunity/netbox:v4.7.3
|
|
69
|
+
COMPOSE: -f tests/e2e/docker-compose.yml -f tests/e2e/docker-compose.branching.yml
|
|
70
|
+
steps:
|
|
71
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
72
|
+
- uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
73
|
+
- name: Sync deps
|
|
74
|
+
run: uv sync --frozen
|
|
75
|
+
- name: Build and start NetBox with Branching
|
|
76
|
+
run: docker compose $COMPOSE up -d --build
|
|
77
|
+
- name: Wait for NetBox
|
|
78
|
+
run: tests/e2e/wait_for_netbox.sh
|
|
79
|
+
- name: Run branching e2e tests
|
|
80
|
+
env:
|
|
81
|
+
NSC_E2E: '1'
|
|
82
|
+
NSC_E2E_BRANCHING: '1'
|
|
83
|
+
NSC_URL: http://127.0.0.1:8080
|
|
84
|
+
NSC_TOKEN: '0123456789abcdef0123456789abcdef01234567'
|
|
85
|
+
run: uv run pytest tests/e2e/test_branching.py -v
|
|
86
|
+
- name: Dump container logs on failure
|
|
87
|
+
if: failure()
|
|
88
|
+
run: docker compose $COMPOSE logs
|
|
89
|
+
- name: Stop NetBox
|
|
90
|
+
if: always()
|
|
91
|
+
run: docker compose $COMPOSE down -v
|
|
@@ -12,9 +12,9 @@ jobs:
|
|
|
12
12
|
lint:
|
|
13
13
|
runs-on: ubuntu-latest
|
|
14
14
|
steps:
|
|
15
|
-
- uses: actions/checkout@v7
|
|
15
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
16
16
|
- name: Install uv
|
|
17
|
-
uses: astral-sh/setup-uv@
|
|
17
|
+
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
18
18
|
with:
|
|
19
19
|
enable-cache: true
|
|
20
20
|
- name: Install Python
|
|
@@ -31,9 +31,9 @@ jobs:
|
|
|
31
31
|
docs-reference-fresh:
|
|
32
32
|
runs-on: ubuntu-latest
|
|
33
33
|
steps:
|
|
34
|
-
- uses: actions/checkout@v7
|
|
34
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
35
35
|
- name: Install uv
|
|
36
|
-
uses: astral-sh/setup-uv@
|
|
36
|
+
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
37
37
|
with:
|
|
38
38
|
enable-cache: true
|
|
39
39
|
- name: Install Python
|
|
@@ -46,9 +46,9 @@ jobs:
|
|
|
46
46
|
agents-md-fresh:
|
|
47
47
|
runs-on: ubuntu-latest
|
|
48
48
|
steps:
|
|
49
|
-
- uses: actions/checkout@v7
|
|
49
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
50
50
|
- name: Install uv
|
|
51
|
-
uses: astral-sh/setup-uv@
|
|
51
|
+
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
52
52
|
with:
|
|
53
53
|
enable-cache: true
|
|
54
54
|
- name: Install Python
|
|
@@ -39,7 +39,7 @@ jobs:
|
|
|
39
39
|
# prerequisites).
|
|
40
40
|
steps:
|
|
41
41
|
- name: Checkout (full history for changelog notes)
|
|
42
|
-
uses: actions/checkout@
|
|
42
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
43
43
|
with:
|
|
44
44
|
fetch-depth: 0
|
|
45
45
|
|
|
@@ -62,7 +62,7 @@ jobs:
|
|
|
62
62
|
echo "Tag $GITHUB_REF_NAME ($GITHUB_SHA) is on main."
|
|
63
63
|
|
|
64
64
|
- name: Install uv
|
|
65
|
-
uses: astral-sh/setup-uv@
|
|
65
|
+
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
66
66
|
with:
|
|
67
67
|
enable-cache: true
|
|
68
68
|
|
|
@@ -110,7 +110,7 @@ jobs:
|
|
|
110
110
|
fi
|
|
111
111
|
|
|
112
112
|
- name: Publish to PyPI (trusted publishing)
|
|
113
|
-
uses: pypa/gh-action-pypi-publish@release/v1
|
|
113
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
114
114
|
with:
|
|
115
115
|
# No `password:` — trusted publishing uses the OIDC token bound
|
|
116
116
|
# to id-token: write above. PyPI must have a Trusted Publisher
|
|
@@ -16,9 +16,9 @@ jobs:
|
|
|
16
16
|
matrix:
|
|
17
17
|
python: ["3.12", "3.13", "3.14"]
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@v7
|
|
19
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
20
20
|
- name: Install uv
|
|
21
|
-
uses: astral-sh/setup-uv@
|
|
21
|
+
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
|
22
22
|
with:
|
|
23
23
|
enable-cache: true
|
|
24
24
|
- name: Install Python
|
|
@@ -20,6 +20,7 @@ This is the contributor guide for AI agents (and humans!) modifying this repo. T
|
|
|
20
20
|
- `nsc/config/` — config loader + Pydantic models + ruamel.yaml round-trip writer.
|
|
21
21
|
- `nsc/cache/` — disk cache for generated command-models.
|
|
22
22
|
- `nsc/auth/` — login verification helpers (pre-flight probes, token rotate).
|
|
23
|
+
- `nsc/branching/` — NetBox Branching: branch name→schema_id resolution, lifecycle API calls, job polling. Framework-free; `nsc/http` must not import it (the client takes a resolver callable).
|
|
23
24
|
- `nsc/aliases/` — curated alias resolver (`ls`, `get`, `rm`, `search`). Framework-free.
|
|
24
25
|
- `nsc/completion/` — dynamic shell-completion: framework-free providers + cheap on-disk cache probe + Typer `shell_complete` callbacks.
|
|
25
26
|
- `nsc/skill/` — bundle-path helper for the portable `SKILL.md` shipped in the wheel.
|
|
@@ -2,6 +2,115 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to netbox-super-cli are tracked here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loosely. From v1.0.0 onward, releases follow [Semantic Versioning](https://semver.org/) and the version in `pyproject.toml` matches the git tag. Pre-1.0 milestones (Phase 1-5) were pinned by tag while `pyproject.toml` stayed at `0.0.1`.
|
|
4
4
|
|
|
5
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
## v1.8.1 — 2026-10-22
|
|
8
|
+
|
|
9
|
+
Patch release. Fixes two NetBox Branching issues found after v1.8.0.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **`--branch` after a subcommand no longer switches branches** ([#170]). It is
|
|
14
|
+
a global option only before the subcommand. After it, `--branch` belongs to
|
|
15
|
+
that command (for example a plugin's `branch` filter) and is left alone.
|
|
16
|
+
- **Branch failures while loading `--saved` filters honour `-o json`** ([#173]).
|
|
17
|
+
They now emit the branch error's structured envelope (with its usual exit
|
|
18
|
+
code) in the requested format instead of falling through to the catch-all
|
|
19
|
+
table renderer. `nsc --branch X <meta command>` (e.g. `profiles list`) is
|
|
20
|
+
also recognised as a meta command again instead of bootstrapping the schema.
|
|
21
|
+
|
|
22
|
+
## v1.8.0 — 2026-10-22
|
|
23
|
+
|
|
24
|
+
Minor release. Adds NetBox Branching support (`--branch`, `NSC_BRANCH`,
|
|
25
|
+
`nsc branch …`), so changes can be staged in a branch, reviewed and merged.
|
|
26
|
+
Also adds OS keyring token storage, lazy TUI pagination with CLI truncation
|
|
27
|
+
notices, and a fix for `nsc login` reporting the wrong user.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **NetBox Branching support** ([#166]). Run any command inside a
|
|
32
|
+
[NetBox Branching](https://netboxlabs.com/docs/extensions/branching/) branch
|
|
33
|
+
with `--branch NAME`, `NSC_BRANCH`, or a sticky per-profile branch set by
|
|
34
|
+
`nsc branch use NAME` (`--branch main` forces main). nsc resolves the name
|
|
35
|
+
to the plugin's `schema_id` and sends `X-NetBox-Branch` on every request.
|
|
36
|
+
Each command run in a branch prints `⎇ branch: <name>` on stderr, and the
|
|
37
|
+
TUI header shows it. A missing or non-`ready` branch fails loudly (exit
|
|
38
|
+
9/12) and never falls back to main. New `nsc branch` group: `list`, `show`,
|
|
39
|
+
`current`, `create` (waits until ready, `--use`), `use` / `use --main`,
|
|
40
|
+
`diff`, and `sync` / `merge` / `revert` / `archive` / `delete`. Like every
|
|
41
|
+
nsc write, these are dry-run unless you pass `--apply`. Conflicts exit 10
|
|
42
|
+
with `details.conflicts`, and `--acknowledge-conflicts` proceeds anyway.
|
|
43
|
+
Targets NetBox 4.7 with `netboxlabs-netbox-branching` 1.2.x; a new
|
|
44
|
+
`e2e-branching` CI job runs it live. See the
|
|
45
|
+
[branching guide](docs/guides/branching.md).
|
|
46
|
+
- **OS keyring token storage** ([#1]). A new `token: !keyring NAME` config tag
|
|
47
|
+
resolves the token from the OS keyring (macOS Keychain, Secret Service,
|
|
48
|
+
Windows Credential Manager) under service `nsc`, username `NAME`.
|
|
49
|
+
`nsc login --new|--rotate --store keyring [--keyring-name NAME]` verifies the
|
|
50
|
+
token, writes it to the keyring, and stores only the `!keyring` reference in
|
|
51
|
+
`~/.nsc/config.yaml`, so the plaintext token never touches disk. Any
|
|
52
|
+
invocation that builds the dynamic command tree reads the keyring, including
|
|
53
|
+
bare `nsc` and `nsc --help`; shell completion and the meta commands
|
|
54
|
+
(`config`, `profiles`, `cache`, `init`, `commands`, `skill`) do not. A missing
|
|
55
|
+
entry or an unavailable backend yields a `config` error envelope (exit 12),
|
|
56
|
+
except that `--help` on a static command still prints usage. `nsc login`
|
|
57
|
+
refuses to overwrite a keyring entry that another profile still references
|
|
58
|
+
(for example after `nsc profiles rename`) and asks for a distinct
|
|
59
|
+
`--keyring-name`. `keyring`
|
|
60
|
+
is a new core dependency, imported lazily so it adds no startup cost. See
|
|
61
|
+
the new [OS keyring storage guide](docs/guides/keyring.md).
|
|
62
|
+
`--keyring-name` is stripped of surrounding whitespace, and a blank name is
|
|
63
|
+
rejected as a usage error before the token prompt.
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
|
|
67
|
+
- **`nsc login` / `nsc profiles add` no longer report a random user** ([#150]).
|
|
68
|
+
The identity probe used to take the owner of the first row of
|
|
69
|
+
`/api/users/tokens/`, which for admins is often another user's token. The
|
|
70
|
+
caller is now identified from the token they presented: v2 (`nbt_…`) tokens
|
|
71
|
+
are looked up by their non-secret key id; v1 tokens are matched client-side
|
|
72
|
+
against the retrievable plaintext when NetBox exposes it
|
|
73
|
+
(`ALLOW_TOKEN_RETRIEVAL`; the plaintext is never sent in a query string), or
|
|
74
|
+
by every visible token sharing one owner. When the user cannot be determined reliably, nsc prints
|
|
75
|
+
`authenticated (user unknown)` instead of guessing.
|
|
76
|
+
- **`nsc tui` lists are no longer capped at the first page** ([#151]). The list
|
|
77
|
+
screen loads 100 rows at a time and fetches the next chunk (following NetBox
|
|
78
|
+
`next` links) when the cursor reaches the last row or you press <kbd>m</kbd>.
|
|
79
|
+
The header shows `N of M` (rows loaded vs. the server's `count`). Loading stops
|
|
80
|
+
at 10,000 rows with a hint to filter instead. A page that fails mid-chunk
|
|
81
|
+
keeps the rows already received (retry with <kbd>m</kbd>), and a refresh no
|
|
82
|
+
longer drops selections made beyond the first chunk.
|
|
83
|
+
- **A negative `--limit` is now a usage error** instead of a Python traceback,
|
|
84
|
+
and `defaults.page_size` must be at least 1.
|
|
85
|
+
- **CLI `list` / `ls` / `search` now report truncation** ([#151]). When the
|
|
86
|
+
default page size hides records the server still has, a one-line
|
|
87
|
+
`nsc: showing 50 of 1234 results; pass --all ...` notice is printed on stderr
|
|
88
|
+
(stdout is unchanged). The default page also no longer fetches one extra page
|
|
89
|
+
from the server just to discard it.
|
|
90
|
+
- **Pages after the first keep multi-value filters** ([#151]). Following a
|
|
91
|
+
NetBox `next` link no longer drops repeated query keys, so
|
|
92
|
+
`--site a --site b --all` returns both sites on every page.
|
|
93
|
+
- **Pagination works when NetBox is served under a sub-path** (`BASE_PATH`,
|
|
94
|
+
e.g. `https://host/netbox`). The second and later pages no longer 404 from a
|
|
95
|
+
doubled path prefix.
|
|
96
|
+
|
|
97
|
+
### Changed
|
|
98
|
+
|
|
99
|
+
- `NetBoxClient.paginate` now returns a lazy, resumable `Pager`
|
|
100
|
+
(`nsc/http/pagination.py`) exposing the server `total` and `has_more`, shared
|
|
101
|
+
by the CLI and the TUI.
|
|
102
|
+
- `nsc login --store` now rejects unknown values. Previously any value other
|
|
103
|
+
than `env` silently fell back to plaintext, so a typo could write the token
|
|
104
|
+
to disk. `nsc login --rotate` with no `--store` keeps an existing
|
|
105
|
+
`!keyring` reference instead of replacing it with plaintext.
|
|
106
|
+
|
|
107
|
+
[#1]: https://github.com/thomaschristory/netbox-super-cli/issues/1
|
|
108
|
+
[#166]: https://github.com/thomaschristory/netbox-super-cli/issues/166
|
|
109
|
+
[#170]: https://github.com/thomaschristory/netbox-super-cli/issues/170
|
|
110
|
+
[#173]: https://github.com/thomaschristory/netbox-super-cli/issues/173
|
|
111
|
+
[#150]: https://github.com/thomaschristory/netbox-super-cli/issues/150
|
|
112
|
+
[#151]: https://github.com/thomaschristory/netbox-super-cli/issues/151
|
|
113
|
+
|
|
5
114
|
## v1.7.0 — 2026-09-10
|
|
6
115
|
|
|
7
116
|
Minor release. Migrates the HTTP stack from `httpx` to Pydantic's maintained
|
|
@@ -13,6 +13,7 @@ This is the contributor guide for AI agents (and humans!) modifying this repo. T
|
|
|
13
13
|
- `nsc/config/` — config loader + Pydantic models + ruamel.yaml round-trip writer.
|
|
14
14
|
- `nsc/cache/` — disk cache for generated command-models.
|
|
15
15
|
- `nsc/auth/` — login verification helpers (pre-flight probes, token rotate).
|
|
16
|
+
- `nsc/branching/` — NetBox Branching: branch name→schema_id resolution, lifecycle API calls, job polling. Framework-free; `nsc/http` must not import it (the client takes a resolver callable).
|
|
16
17
|
- `nsc/aliases/` — curated alias resolver (`ls`, `get`, `rm`, `search`). Framework-free.
|
|
17
18
|
- `nsc/completion/` — dynamic shell-completion: framework-free providers + cheap on-disk cache probe + Typer `shell_complete` callbacks.
|
|
18
19
|
- `nsc/skill/` — bundle-path helper for the portable `SKILL.md` shipped in the wheel.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: netbox-super-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.1
|
|
4
4
|
Summary: Dynamic NetBox CLI generated from the live OpenAPI schema.
|
|
5
5
|
Project-URL: Homepage, https://github.com/thomaschristory/netbox-super-cli
|
|
6
6
|
Project-URL: Documentation, https://thomaschristory.github.io/netbox-super-cli/
|
|
@@ -24,6 +24,7 @@ Classifier: Topic :: System :: Networking
|
|
|
24
24
|
Requires-Python: >=3.12
|
|
25
25
|
Requires-Dist: click>=8.1
|
|
26
26
|
Requires-Dist: httpx2>=2.5
|
|
27
|
+
Requires-Dist: keyring>=25.0
|
|
27
28
|
Requires-Dist: platformdirs>=4.2
|
|
28
29
|
Requires-Dist: pydantic>=2.7
|
|
29
30
|
Requires-Dist: rich>=13.7
|
|
@@ -64,6 +65,7 @@ One binary, any NetBox version, every plugin endpoint — the schema, not hand-w
|
|
|
64
65
|
- **Plugins just work.** If your install has plugins, their endpoints appear as commands automatically.
|
|
65
66
|
- **Multi-instance.** Named profiles per NetBox instance, plus env-var overrides.
|
|
66
67
|
- **Safe by default.** POST/PATCH/PUT/DELETE preview as dry-runs unless you pass `--apply`.
|
|
68
|
+
- **NetBox Branching.** Stage changes in a branch (`--branch`, `NSC_BRANCH`, `nsc branch use`), review with `nsc branch diff`, merge with `nsc branch merge --apply`. See [the guide](docs/guides/branching.md).
|
|
67
69
|
- **Agent-friendly.** Deterministic command shape, machine-readable JSON output, stable error envelope with documented exit codes.
|
|
68
70
|
- **Interactive TUI.** `nsc tui` opens a keyboard-driven terminal UI — see below.
|
|
69
71
|
|
|
@@ -208,6 +210,25 @@ The wire body sent to NetBox is **not** redacted — only the audit log. A faile
|
|
|
208
210
|
|
|
209
211
|
For a stricter posture, set `audit_redaction: full` in `~/.nsc/config.yaml` (the default is `safe`, the field-level redaction described above). In `full` mode every audit line keeps only `{method, url, status_code, timestamp, profile}` — all request and response bodies are dropped, and the `url` is sanitized (query string and any `user:pass@` credentials stripped).
|
|
210
212
|
|
|
213
|
+
## NetBox Branching
|
|
214
|
+
|
|
215
|
+
If your NetBox runs the [Branching plugin](https://netboxlabs.com/docs/extensions/branching/),
|
|
216
|
+
any command can stage its changes in a branch for review:
|
|
217
|
+
|
|
218
|
+
```sh
|
|
219
|
+
nsc branch create add-london --use # create, wait until ready, make it sticky
|
|
220
|
+
nsc dcim sites create -f london.yaml --apply # lands in the branch; stderr shows "⎇ branch: add-london"
|
|
221
|
+
nsc branch diff # review the staged changes
|
|
222
|
+
nsc branch merge # dry-run, validated server-side
|
|
223
|
+
nsc branch merge --apply # merge into main
|
|
224
|
+
nsc branch use --main # back to main
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
`--branch NAME` and `NSC_BRANCH` select a branch for a single command or a
|
|
228
|
+
whole shell, and agents should use these. A merged, missing or not-ready branch
|
|
229
|
+
fails loudly and never falls back to main. See the
|
|
230
|
+
[branching guide](docs/guides/branching.md).
|
|
231
|
+
|
|
211
232
|
## Curated aliases
|
|
212
233
|
|
|
213
234
|
`nsc ls`, `nsc get`, `nsc rm`, and `nsc search` are short verbs over the dynamic
|
|
@@ -29,6 +29,7 @@ One binary, any NetBox version, every plugin endpoint — the schema, not hand-w
|
|
|
29
29
|
- **Plugins just work.** If your install has plugins, their endpoints appear as commands automatically.
|
|
30
30
|
- **Multi-instance.** Named profiles per NetBox instance, plus env-var overrides.
|
|
31
31
|
- **Safe by default.** POST/PATCH/PUT/DELETE preview as dry-runs unless you pass `--apply`.
|
|
32
|
+
- **NetBox Branching.** Stage changes in a branch (`--branch`, `NSC_BRANCH`, `nsc branch use`), review with `nsc branch diff`, merge with `nsc branch merge --apply`. See [the guide](docs/guides/branching.md).
|
|
32
33
|
- **Agent-friendly.** Deterministic command shape, machine-readable JSON output, stable error envelope with documented exit codes.
|
|
33
34
|
- **Interactive TUI.** `nsc tui` opens a keyboard-driven terminal UI — see below.
|
|
34
35
|
|
|
@@ -173,6 +174,25 @@ The wire body sent to NetBox is **not** redacted — only the audit log. A faile
|
|
|
173
174
|
|
|
174
175
|
For a stricter posture, set `audit_redaction: full` in `~/.nsc/config.yaml` (the default is `safe`, the field-level redaction described above). In `full` mode every audit line keeps only `{method, url, status_code, timestamp, profile}` — all request and response bodies are dropped, and the `url` is sanitized (query string and any `user:pass@` credentials stripped).
|
|
175
176
|
|
|
177
|
+
## NetBox Branching
|
|
178
|
+
|
|
179
|
+
If your NetBox runs the [Branching plugin](https://netboxlabs.com/docs/extensions/branching/),
|
|
180
|
+
any command can stage its changes in a branch for review:
|
|
181
|
+
|
|
182
|
+
```sh
|
|
183
|
+
nsc branch create add-london --use # create, wait until ready, make it sticky
|
|
184
|
+
nsc dcim sites create -f london.yaml --apply # lands in the branch; stderr shows "⎇ branch: add-london"
|
|
185
|
+
nsc branch diff # review the staged changes
|
|
186
|
+
nsc branch merge # dry-run, validated server-side
|
|
187
|
+
nsc branch merge --apply # merge into main
|
|
188
|
+
nsc branch use --main # back to main
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`--branch NAME` and `NSC_BRANCH` select a branch for a single command or a
|
|
192
|
+
whole shell, and agents should use these. A merged, missing or not-ready branch
|
|
193
|
+
fails loudly and never falls back to main. See the
|
|
194
|
+
[branching guide](docs/guides/branching.md).
|
|
195
|
+
|
|
176
196
|
## Curated aliases
|
|
177
197
|
|
|
178
198
|
`nsc ls`, `nsc get`, `nsc rm`, and `nsc search` are short verbs over the dynamic
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
Only the latest release gets security fixes.
|
|
6
|
+
|
|
7
|
+
## Reporting a vulnerability
|
|
8
|
+
|
|
9
|
+
Do not open a public issue. Use the private vulnerability reporting of GitHub:
|
|
10
|
+
[Report a vulnerability](https://github.com/thomaschristory/netbox-super-cli/security/advisories/new)
|
|
11
|
+
(**Security > Report a vulnerability** on the repository). Only the maintainer sees the report.
|
|
12
|
+
The maintainer replies, fixes the problem, and publishes an advisory with the fix.
|
|
@@ -20,6 +20,15 @@
|
|
|
20
20
|
`final_attempt`; redaction is applied on every write, so a failed
|
|
21
21
|
retry never unredacts.
|
|
22
22
|
- Pagination helper that follows `next` URLs (used by `--all`).
|
|
23
|
+
- Optional NetBox Branching context. Given a `branch_resolver`, the client
|
|
24
|
+
resolves the branch lazily on its first request: the resolver's own lookups
|
|
25
|
+
go out unbranched, and every later request carries
|
|
26
|
+
`X-NetBox-Branch: <schema_id>`. Resolution is serialized under a lock, so
|
|
27
|
+
concurrent `--workers` threads wait instead of racing ahead without the
|
|
28
|
+
header. A failed resolution is stored and raised again on every later call,
|
|
29
|
+
so once a branch is selected no request can reach main. The resolver
|
|
30
|
+
itself lives in `nsc/branching/` (`nsc/http` does not import it), and
|
|
31
|
+
`nsc branch …` commands build a client without one.
|
|
23
32
|
- Audit log appender at `~/.nsc/logs/audit.jsonl` — written for writes
|
|
24
33
|
always, and for any request when `--debug` is set.
|
|
25
34
|
|
|
@@ -16,6 +16,7 @@ nsc/
|
|
|
16
16
|
├── config/ # Pydantic config models + ruamel.yaml writer
|
|
17
17
|
├── cache/ # On-disk cache for generated CommandModels
|
|
18
18
|
├── auth/ # Login verification helpers (verify probe, token rotate)
|
|
19
|
+
├── branching/ # NetBox Branching: branch lookup, lifecycle calls, job polling
|
|
19
20
|
├── aliases/ # Curated alias resolver (ls/get/rm/search)
|
|
20
21
|
├── completion/ # Dynamic shell-completion: providers + cache probe + Typer callbacks
|
|
21
22
|
├── skill/ # Bundle-path helper for the portable SKILL.md
|
|
@@ -70,6 +70,22 @@ nsc dcim devices create --field name=foo --field site=1 --apply
|
|
|
70
70
|
Add `--explain` to a dry-run to see the schema reasoning ("PATCH because of
|
|
71
71
|
operationId `dcim_devices_partial_update`").
|
|
72
72
|
|
|
73
|
+
## Branches (NetBox Branching)
|
|
74
|
+
|
|
75
|
+
If your server runs the NetBox Branching plugin, any command can run inside a
|
|
76
|
+
branch instead of main. Pick one with `--branch NAME`, `NSC_BRANCH=NAME`, or
|
|
77
|
+
make it sticky on the profile with `nsc branch use NAME`. While a branch is
|
|
78
|
+
active, every command prints `⎇ branch: NAME` on stderr. If the branch can't be
|
|
79
|
+
used (merged, missing, not ready), the command fails without sending anything.
|
|
80
|
+
It never quietly falls back to main. See [NetBox Branching](../guides/branching.md).
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
nsc branch create add-london --use
|
|
84
|
+
nsc dcim sites create --field name=London --field slug=london --apply # staged in the branch
|
|
85
|
+
nsc branch diff
|
|
86
|
+
nsc branch merge --apply
|
|
87
|
+
```
|
|
88
|
+
|
|
73
89
|
## Audit log
|
|
74
90
|
|
|
75
91
|
Every wire request and its response are appended to
|
|
@@ -54,9 +54,13 @@ nsc login --rotate --profile prod # rotate the token
|
|
|
54
54
|
nsc login --fetch-schema # verify, then fetch & cache the live schema
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
`nsc login` probes `GET /api/status/` and `GET /api/users/tokens
|
|
57
|
+
`nsc login` probes `GET /api/status/` and `GET /api/users/tokens/`
|
|
58
58
|
(both must succeed) and prints `✓ authenticated as <user>, NetBox <version>`
|
|
59
|
-
on success.
|
|
59
|
+
on success. NetBox has no "current user" endpoint, so the user is derived from
|
|
60
|
+
the token you presented; when that can't be done reliably (e.g. a v1 token
|
|
61
|
+
held by an admin who can see other users' tokens) it prints
|
|
62
|
+
`✓ authenticated (user unknown), NetBox <version>` rather than guessing.
|
|
63
|
+
On failure it emits the standard auth error envelope
|
|
60
64
|
(`type: auth`, exit 8).
|
|
61
65
|
|
|
62
66
|
`--new` requires both `--profile` and `--url`, prompts for the token
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# NetBox Branching
|
|
2
|
+
|
|
3
|
+
If your NetBox runs the [NetBox Branching plugin](https://netboxlabs.com/docs/extensions/branching/)
|
|
4
|
+
(`netboxlabs-netbox-branching`), `nsc` can make your changes in a **branch**
|
|
5
|
+
instead of on main. You stage writes in the branch, review the diff, and then
|
|
6
|
+
merge them into main. This works the same way for people and for AI agents.
|
|
7
|
+
|
|
8
|
+
Requires NetBox 4.7 and plugin 1.2.x (tested against NetBox 4.7.3 and plugin 1.2.2).
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
nsc branch create add-london --use # create, wait until ready, make it sticky
|
|
12
|
+
nsc dcim sites create -f london.yaml --apply # lands in the branch, not main
|
|
13
|
+
nsc branch diff # review what the branch changes
|
|
14
|
+
nsc branch merge # dry-run: validates the merge server-side
|
|
15
|
+
nsc branch merge --apply # merge into main
|
|
16
|
+
nsc branch use --main # back to main
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Choosing the branch
|
|
20
|
+
|
|
21
|
+
Every command, including dynamic resource commands, aliases and the TUI, runs
|
|
22
|
+
in the active branch. `nsc` sends the plugin's `X-NetBox-Branch` header with
|
|
23
|
+
the branch's `schema_id`. You refer to a branch by name, or by schema_id if
|
|
24
|
+
you prefer.
|
|
25
|
+
|
|
26
|
+
The active branch comes from the first of these that is set:
|
|
27
|
+
|
|
28
|
+
| Source | Example | Lifetime |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `--branch NAME` | `nsc --branch add-london ls sites` | one command |
|
|
31
|
+
| `NSC_BRANCH` | `export NSC_BRANCH=add-london` | the shell / CI job |
|
|
32
|
+
| profile `branch:` | written by `nsc branch use NAME` | sticky, until `nsc branch use --main` |
|
|
33
|
+
|
|
34
|
+
`--branch main` or `NSC_BRANCH=main` forces main for that invocation even when
|
|
35
|
+
the profile has a sticky branch.
|
|
36
|
+
|
|
37
|
+
`--branch` is a global option and must come **before** the subcommand
|
|
38
|
+
(`nsc --branch X dcim sites list`). After the subcommand, `--branch` belongs to
|
|
39
|
+
that command, for example the Branching plugin's own `changes list` filter, and
|
|
40
|
+
doesn't switch branches.
|
|
41
|
+
|
|
42
|
+
`nsc branch use` needs a saved profile to store the branch on. With only
|
|
43
|
+
`NSC_URL`/`NSC_TOKEN` set (no profile), use `NSC_BRANCH` or `--branch`.
|
|
44
|
+
|
|
45
|
+
## Knowing where you are
|
|
46
|
+
|
|
47
|
+
When a branch is active, every command prints one line to **stderr**:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
⎇ branch: add-london
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
stdout is untouched, so `-o json` output piped elsewhere stays clean. The TUI
|
|
54
|
+
shows the branch in its header in the warning colour. `nsc branch current`
|
|
55
|
+
prints the active branch and where it came from (`flag`, `env` or `profile`),
|
|
56
|
+
or `main`.
|
|
57
|
+
|
|
58
|
+
Every request made in a branch is recorded in the [audit log](audit-log.md)
|
|
59
|
+
with its `X-Netbox-Branch` header (the branch's schema_id). When a command
|
|
60
|
+
fails while a branch is active, its error envelope names the branch in
|
|
61
|
+
`details.branch`, whatever the failure is.
|
|
62
|
+
|
|
63
|
+
A branch that is literally named `main` can still be selected by its
|
|
64
|
+
schema_id. `nsc branch use` stores the schema_id for such a branch, because the
|
|
65
|
+
name would read back as "force main".
|
|
66
|
+
|
|
67
|
+
## When the branch can't be used
|
|
68
|
+
|
|
69
|
+
If the active branch doesn't exist, or exists but isn't `ready` (it's
|
|
70
|
+
merged, archived, still provisioning, or failed), the command **fails without
|
|
71
|
+
sending anything** and never falls back to main:
|
|
72
|
+
|
|
73
|
+
| Situation | Error type | Exit |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| Branching plugin not installed | `config` | 12 |
|
|
76
|
+
| Branch not found | `not_found` | 9 |
|
|
77
|
+
| Branch not `ready` (e.g. merged) | `config` | 12 |
|
|
78
|
+
| Name matches one branch and schema_id of another | `input_error` | 4 |
|
|
79
|
+
|
|
80
|
+
The message says how to get back to main: `nsc branch use --main`, or
|
|
81
|
+
`--branch main` for a single command. `nsc branch …` commands never run inside
|
|
82
|
+
a branch, so `nsc branch use --main` always works.
|
|
83
|
+
|
|
84
|
+
## Commands
|
|
85
|
+
|
|
86
|
+
| Command | What it does |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `nsc branch list` | All branches; the active one has `active: true`. |
|
|
89
|
+
| `nsc branch show [NAME]` | One branch (default: the active one). |
|
|
90
|
+
| `nsc branch current` | Active branch and its source, or `main`. No network call. |
|
|
91
|
+
| `nsc branch create NAME [--description] [--use] [--no-wait]` | Create the branch and wait until it's `ready`. `--use` then makes it sticky. |
|
|
92
|
+
| `nsc branch use NAME` / `--main` | Set / clear the profile's sticky branch. Checks that the branch is `ready` first. |
|
|
93
|
+
| `nsc branch diff [NAME]` | Staged changes: action, object type, object, changed fields. `-o json` gives the full plugin records. |
|
|
94
|
+
| `nsc branch sync [NAME]` | Pull main's changes into the branch. |
|
|
95
|
+
| `nsc branch merge [NAME]` | Merge the branch into main. |
|
|
96
|
+
| `nsc branch revert [NAME]` | Undo a merged branch on main. |
|
|
97
|
+
| `nsc branch archive [NAME]` | Archive a merged branch (drops its schema). |
|
|
98
|
+
| `nsc branch delete NAME` | Delete a branch. |
|
|
99
|
+
|
|
100
|
+
### Dry-run by default
|
|
101
|
+
|
|
102
|
+
Like every other `nsc` write, `sync`, `merge`, `revert`, `archive` and
|
|
103
|
+
`delete` change nothing unless you pass `--apply`:
|
|
104
|
+
|
|
105
|
+
- `sync`, `merge` and `revert` without `--apply` still run the plugin's job
|
|
106
|
+
with `commit: false`, so the server checks that the operation would succeed
|
|
107
|
+
and then rolls it back.
|
|
108
|
+
- `archive` and `delete` without `--apply` only print what they would do.
|
|
109
|
+
|
|
110
|
+
`sync`, `merge` and `revert` wait for the background job to finish (up to
|
|
111
|
+
`--timeout`, 600 s by default) and print the job's log lines on stderr. Pass
|
|
112
|
+
`--no-wait` to return as soon as the job is queued.
|
|
113
|
+
|
|
114
|
+
A job that ends in `errored` exits **4** (`validation`), with the job's error
|
|
115
|
+
in `details.job_error`. This happens, for example, when a Change Request
|
|
116
|
+
policy blocks the merge.
|
|
117
|
+
|
|
118
|
+
### Conflicts
|
|
119
|
+
|
|
120
|
+
If main and the branch changed the same fields of an object, `sync` and
|
|
121
|
+
`merge` fail with exit **10** (`conflict`), and `details.conflicts` lists each
|
|
122
|
+
object together with its original, branch and main values. After reviewing
|
|
123
|
+
them, re-run with `--acknowledge-conflicts` to proceed; the branch's values
|
|
124
|
+
win.
|
|
125
|
+
|
|
126
|
+
## For agents
|
|
127
|
+
|
|
128
|
+
Agents should set `NSC_BRANCH` rather than `nsc branch use`. It works without
|
|
129
|
+
a saved profile, and it doesn't change the user's config:
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
nsc branch create agent-change-123 -o json
|
|
133
|
+
export NSC_BRANCH=agent-change-123
|
|
134
|
+
nsc dcim devices create -f devices.ndjson --apply -o json
|
|
135
|
+
nsc branch diff agent-change-123 -o json # hand this to a human for review
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The commands are the same for people and agents. Whether an agent may run
|
|
139
|
+
`nsc branch merge --apply` is up to the session's own rules; `nsc` doesn't
|
|
140
|
+
enforce it.
|