Skip to content

feat: unify SCCFM interactive command and token configuration - #24

Merged
huides00 merged 3 commits into
mainfrom
LH-114358/interactive-and-token-unify
Aug 18, 2026
Merged

feat: unify SCCFM interactive command and token configuration#24
huides00 merged 3 commits into
mainfrom
LH-114358/interactive-and-token-unify

Conversation

@Scoombe

@Scoombe Scoombe commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Replace devkit with sccfm-cli-interactive and consolidate CLI and Ansible token configuration into a shared secure profile.

Replace devkit with sccfm-cli-interactive and consolidate CLI and
Ansible token configuration into a shared secure profile.
"Import profiles from the former Ansible Vault token store",
_import_legacy_vault,
),
("run-cli", "Run an sccfm-cli command interactively", _run_cli_commands),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Protect sensitive CLI parameters

The run-cli path still treats api_token like ordinary text: _execute_cli_command() uses questionary.text, adds the value to argv, and prints the complete command. Because it supplies --api-token explicitly, Click's new hide_input=True prompt is bypassed. Please propagate sensitive/hidden-input metadata into CliParam, use a password prompt, and redact the rendered command.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5d69315 and completed in 6ee20e2. CliParam now carries hide_input, secret values use questionary.password, rendered commands redact them, and secret-bearing CLI invocations run in-process so the raw value is not exposed through OS process arguments. Regression coverage is in test_execute_cli_command_masks_secrets_and_uses_password_prompt.

_import_legacy_vault,
),
("run-cli", "Run an sccfm-cli command interactively", _run_cli_commands),
("run-ansible", "Run an Ansible example playbook", _run_ansible_examples),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Make the Vault argument conditional

The new profile setup no longer creates .vault_pass, and Vault is optional for read-only examples, but _run_ansible_examples() always supplies --vault-password-file .vault_pass. Those examples fail after the documented profile-only setup. Please add the argument only when the selected playbook requires Vault and the password file exists.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5d69315. _run_ansible_examples() now checks _playbook_requires_vault() and only adds --vault-password-file when the selected playbook references Vault variables and .vault_pass exists. Both the Vault and non-Vault paths have regression tests.

def configured_sccfm_profile(monkeypatch: MonkeyPatch) -> None:
"""Keep module tests isolated from the user's canonical profile file."""
monkeypatch.setattr(
config_module.ProfileService,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Isolate tests from the real profile path

Patching ProfileService.load is too late to prevent ProfileService.__init__ from inspecting and chmodding the user's ~/.sccfm-cli/config.json. In a restricted environment this caused 184 module-test failures. Please redirect SCCFM_CONFIG to a tmp_path or replace service construction so tests never touch real credential state.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5d69315. The autouse fixture now sets SCCFM_CONFIG to tmp_path / "config.json" before ProfileService is constructed, so module tests cannot inspect or chmod the user's real profile store.

Comment thread sccfm-ansible/plugins/lookup/profile.py Outdated
DOCUMENTATION = r"""
name: profile
author: Cisco SCCFM Team
version_added: "1.0.0"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] Correct the introduction version

This lookup is introduced before collection version 1.0.0, so version_added currently reports it as a future feature. Please set this to the release version that will first contain the plugin.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5d69315. The lookup plugin now declares version_added: "0.39.0", matching the release that will first contain it.

@huides00 huides00 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review focused on the unified interactive/profile flow. Breaking compatibility is intentionally not treated as a concern because this has not been released.

@Scoombe Scoombe left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The consolidation around a canonical named profile store makes sense, and the CLI/Ansible integration is internally consistent. I verified schema export, collection build/discovery, module argument resolution, mypy, and the full test suite (1,181 passing). The failing Docs check is unrelated infrastructure noise: GitHub returned HTTP 429 while downloading actions/jekyll-build-pages.

I found two issues that should be addressed before merge: the interactive runner still exposes API tokens through the child process argument list, and the Python 3.12 implementation breaks the documented native-Windows path. This is a commented review because this GitHub account owns the PR and cannot formally request changes on its own PR.

prompt = f"{param.label}{'' if param.required else ' (leave blank to skip)'}"
single: str | None = questionary.text(prompt).unsafe_ask()
single: str | None = _prompt_param(prompt, param.hide_input)
normalized_value = (single or "").strip()

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Keep the token out of the child process argument list

The new password prompt and rendered-command redaction protect the terminal, but argv still contains the raw token and subprocess.call(argv, ...) exposes it to process listings and process/audit tooling for the lifetime of sccfm-cli. This affects configure --api-token, precisely the credential this change is trying to store securely. Please invoke promptable secret options without placing their values in argv (or execute the Click command in-process through a secret-safe path).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6ee20e2. _invoke_cli() executes any secret-bearing command through Click in the current Python process with standalone_mode=False; only non-secret commands use subprocess.call. The token therefore remains out of OS argv while terminal rendering stays redacted. Regression tests cover both invocation paths.

)
temporary_path = Path(temporary_name)
try:
os.fchmod(file_descriptor, _CONFIG_FILE_MODE)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve the stated Python 3.12 Windows support

os.fchmod was only added on Windows in Python 3.13, while this project targets Python 3.12 and its CLI skill explicitly documents native Windows support. On Python 3.12/Windows every profile save reaches this line and fails before writing the config, so sccfm-cli configure cannot work. Please use a platform-compatible permission path (with an appropriate Windows security strategy) or explicitly narrow the supported platform contract.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6ee20e2. POSIX mode operations are now gated by _SUPPORTS_POSIX_MODES, so Python 3.12 on Windows never calls unavailable os.fchmod or POSIX chmod paths. Windows uses the ACLs inherited from the user's profile directory, and the README/Ansible/agent guidance now documents that behavior. A regression test verifies saving without POSIX mode APIs.

@github-actions

Copy link
Copy Markdown

Consistency Check

No consistency issues found.

Checker output
✓ No issues found across 114 file(s).

@huides00
huides00 merged commit a1e896d into main Aug 18, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants