Repository navigation
enhancement: clarify trust status reasons and help #2648
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,24 +5,31 @@ readonly _base_trust_subcommand_sourced | |
|
|
||
| base_trust_subcommand_usage() { | ||
| cat <<'EOF' | ||
| Purpose: | ||
| Status is read-only: it shows detailed guidance for one project, or a compact | ||
| blocked-first summary of discovered command-bearing projects when no project | ||
| is supplied. Allow records local approval for manifest-declared commands; | ||
| revoke removes local approval. | ||
| See `basectl trust status <project>` for details on what approval covers. | ||
|
|
||
| Usage: | ||
| basectl trust status [project] [options] | ||
| basectl trust allow <project> [options] | ||
| basectl trust revoke <project> [options] | ||
|
|
||
| Options: | ||
| --project <name> Select a project explicitly, including one named help. | ||
| --workspace <path> Workspace directory to scan. Defaults to workspace.root, then BASE_HOME's parent. | ||
| --project <name> Select a project explicitly instead of the | ||
| positional <project> argument. | ||
| --workspace <path> Workspace for status discovery or project | ||
| resolution. Defaults to workspace.root, then | ||
| the parent of BASE_HOME. | ||
| --format <text|csv|tsv|yaml|json> | ||
| Output format for status. Defaults to text. | ||
| --manifest-sha256 <sha256> Expected manifest SHA-256 for allow. | ||
| --test-requirements-sha256 <sha256> | ||
| Expected SHA-256 for the declared test-requirements file. | ||
| -v Enable DEBUG logging for this subcommand. | ||
| -h, --help Show this help text. | ||
|
|
||
| Inspect trust for one project or all discovered projects, and manage local | ||
| approval for manifest-declared project commands. | ||
| EOF | ||
| } | ||
|
|
||
|
|
@@ -36,12 +43,14 @@ Usage: | |
| basectl trust status [project] [options] | ||
|
|
||
| Purpose: | ||
| Show manifest command trust for one project, or for all discovered | ||
| command-bearing projects when no project is supplied. | ||
| Read-only trust inspection. Show detailed status for one project, or a | ||
| compact blocked-first summary of discovered command-bearing projects when no | ||
| project is supplied. | ||
|
|
||
| Options: | ||
| --project <name> Select a project explicitly, including one named help. | ||
| --workspace <path> Workspace directory to scan. | ||
| --project <name> Select a project explicitly instead of using [project]. | ||
| --workspace <path> Workspace to scan for command-bearing projects. | ||
| Defaults to workspace.root, then the parent of BASE_HOME. | ||
| --format <text|csv|tsv|yaml|json> | ||
| Output format. Defaults to text. | ||
| -v Enable DEBUG logging for this subcommand. | ||
|
|
@@ -54,12 +63,14 @@ Usage: | |
| basectl trust allow <project> [options] | ||
|
|
||
| Purpose: | ||
| Approve the current manifest command contract for one project on this | ||
| machine. | ||
| Record local approval for the current manifest command contract on this | ||
| machine. See `basectl trust status <project>` for approval-scope details. | ||
|
|
||
| Options: | ||
| --project <name> Select a project explicitly, including one named help. | ||
| --workspace <path> Workspace directory to scan. | ||
| --project <name> Select a project explicitly instead of using | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: in the parent usage, |
||
| <project>. | ||
| --workspace <path> Workspace used to resolve the project. Defaults | ||
| to workspace.root, then the parent of BASE_HOME. | ||
| --manifest-sha256 <sha256> Require the current manifest to match this digest. | ||
| --test-requirements-sha256 <sha256> | ||
| Require the declared test-requirements file to match this digest. | ||
|
|
@@ -76,10 +87,12 @@ Purpose: | |
| Remove local manifest command approval for one project. | ||
|
|
||
| Options: | ||
| --project <name> Select a project explicitly, including one named help. | ||
| --workspace <path> Workspace directory to scan. | ||
| -v Enable DEBUG logging for this subcommand. | ||
| -h, --help Show this help text. | ||
| --project <name> Select a project explicitly instead of using | ||
| <project>. | ||
| --workspace <path> Workspace used to resolve the project. Defaults | ||
| to workspace.root, then the parent of BASE_HOME. | ||
| -v Enable DEBUG logging for this subcommand. | ||
| -h, --help Show this help text. | ||
| EOF | ||
| ;; | ||
| *) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -153,8 +153,8 @@ def test_workspace_status_text_summarizes_blocked_reasons_before_allowed_project | |
| ) | ||
|
|
||
| assert result.exit_code == 0, result.output | ||
| assert "changed-manifest Blocked Manifest changed" in result.stdout | ||
| assert "changed-requirements Blocked Test requirements changed" in result.stdout | ||
| assert "changed-manifest Blocked Approval stale: manifest" in result.stdout | ||
| assert "changed-requirements Blocked Approval stale: test reqs" in result.stdout | ||
| assert "fresh Blocked Not approved" in result.stdout | ||
| assert "allowed Allowed Approved" in result.stdout | ||
| assert result.stdout.index("changed-manifest Blocked") < result.stdout.index("allowed Allowed") | ||
|
|
@@ -229,6 +229,81 @@ def display_width(value: str) -> int: | |
| assert len({display_width(line.split("Blocked", maxsplit=1)[0]) for line in rows}) == 1 | ||
|
|
||
|
|
||
| def test_workspace_status_reason_labels_survive_narrow_terminal_fitting( | ||
| tmp_path: Path, | ||
| monkeypatch: pytest.MonkeyPatch, | ||
| capsys: pytest.CaptureFixture[str], | ||
| ) -> None: | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth a one-line comment here explaining the budget: at width 60 the 25-character label leaves zero slack (24 + 7 + 25 + 2 gaps of 2 = 60). That is a good thing, since it makes the test fail if the label grows, but a future editor will not know the width and the 40-character name are chosen on purpose. |
||
| _force_terminal_output(monkeypatch) | ||
| monkeypatch.setattr(base_cli_output, "_terminal_width", lambda _stream: 60) | ||
| # At width 60, the 24-character project, 7-character status, and 25-character | ||
| # reason use all columns with two 2-space gaps; the long name forces truncation | ||
| # while the longest reason label fits with zero slack. | ||
| long_project_name = "project-" + "x" * 32 | ||
| assert len(long_project_name) == 40 | ||
| statuses = ( | ||
| engine.TrustStatus( | ||
| status="blocked", | ||
| reason="manifest_changed", | ||
| identity=engine.ManifestCommandTrustIdentity( | ||
| project_name=long_project_name, | ||
| project_root=tmp_path, | ||
| manifest_path=tmp_path / "base_manifest.yaml", | ||
| manifest_sha256="a" * 64, | ||
| identity_key=long_project_name, | ||
| ), | ||
| ), | ||
| engine.TrustStatus( | ||
| status="blocked", | ||
| reason="test_requirements_changed", | ||
| identity=engine.ManifestCommandTrustIdentity( | ||
| project_name="demo", | ||
| project_root=tmp_path, | ||
| manifest_path=tmp_path / "base_manifest.yaml", | ||
| manifest_sha256="b" * 64, | ||
| identity_key="demo", | ||
| ), | ||
| ), | ||
| ) | ||
|
|
||
| engine._print_workspace_status_text(tmp_path, statuses) # pylint: disable=protected-access | ||
|
|
||
| output = capsys.readouterr().out | ||
| rows = [line for line in output.splitlines() if "Blocked" in line] | ||
| assert len(rows) == 2 | ||
| assert any("Approval stale: manifest" in line for line in rows) | ||
| assert any("Approval stale: test reqs" in line for line in rows) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| ("command", "workspace_help", "expect_scan"), | ||
| [ | ||
| ("status", "Workspace directory to scan for command-bearing projects.", True), | ||
| ("require", "Workspace directory used to resolve the project.", False), | ||
| ("allow", "Workspace directory used to resolve the project.", False), | ||
| ("revoke", "Workspace directory used to resolve the project.", False), | ||
| ], | ||
| ) | ||
| def test_trust_python_help_describes_workspace_resolution( | ||
| tmp_path: Path, | ||
| command: str, | ||
| workspace_help: str, | ||
| expect_scan: bool, | ||
| ) -> None: | ||
| result = invoke( | ||
| engine.app, | ||
| [command, "--help"], | ||
| home=tmp_path / "home", | ||
| env={"BASE_HOME": str(tmp_path / "base")}, | ||
| ) | ||
|
|
||
| assert result.exit_code == 0, result.output | ||
| help_text = " ".join(result.stdout.split()) | ||
| assert workspace_help in help_text | ||
| assert "Defaults to workspace.root, then the parent of BASE_HOME." in help_text | ||
| assert ("scan" in help_text) is expect_scan | ||
|
|
||
|
|
||
| def test_workspace_status_reason_fallback_preserves_acronyms() -> None: | ||
| assert engine._workspace_status_reason_label("remote_HTTP_status") == "Remote HTTP Status" # pylint: disable=protected-access | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Convention:
Purpose:now comes beforeUsage:here and in the allow and revoke leaves (lines 62 and 83) and in the parent (line 8). The other 17basectlsubcommand files that have a Purpose section putUsage:first (for exampleci.sh,doctor.sh,gh_issue.sh). #2647 only asked to move the parent summary ahead of Usage. I'd keep Usage first in the three leaves, and for the parent either keep the issue's requested order or accept it as a parent-only exception. Update the new help test accordingly if you move them (it does not depend on order today, since it flattens the text).