skillctl-secure 0.28.2__tar.gz → 0.28.3__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.
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/PKG-INFO +1 -1
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/pyproject.toml +1 -1
- skillctl_secure-0.28.3/skillctl/__init__.py +1 -0
- skillctl_secure-0.28.3/skillctl/findings_tui.py +108 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/tui_interaction.py +9 -1
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/tui_original.py +9 -1
- skillctl_secure-0.28.2/skillctl/__init__.py +0 -1
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/.gitignore +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/LICENSE +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/README.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/__main__.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/authcontrols.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/benchmark.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/browsercontrols.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/bulk_cli.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/bulk_plan.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/bulk_update.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/bulk_update_tui.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/cacheutil.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/candidates.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/catalog.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/catalog_discovery.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/catalog_index.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/catalog_schema.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/catalog_search_cli.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/catalog_search_tui.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/cicdflow.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/cli.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/cli_contract.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/compatibility.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/context_cost.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/context_tui.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/copilot_export.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/coverage.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/dedupe.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/doctor.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/entrypoint.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/environments.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/estimate.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/evidence.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/findings.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/flow.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/governor.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/hardening.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/history_tui.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/iac.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/install_intent.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/install_review.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/intent_diff.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/journal.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/journal_hooks.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/journal_operations.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/lockfile.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/manager.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/models.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/navigation_tui.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/operation_lock.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/packet.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/paths.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/permissions.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/policy.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/policy_editor.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/precision.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/profiles.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/publishers.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/ranking.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/recommendation.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/recommendation_tui.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/reconcile_cli.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/reconcile_recovery.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/reconcile_transaction.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/reconcile_tui.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/reconciliation.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/remote.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/benchmarks/vulnlab/answer-key.yaml +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/benchmarks/vulnlab/target/.env +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/benchmarks/vulnlab/target/.github/workflows/build.yml +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/benchmarks/vulnlab/target/README.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/benchmarks/vulnlab/target/app.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/benchmarks/vulnlab/target/openapi.yaml +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/benchmarks/vulnlab/target/requirements.txt +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/benchmarks/vulnlab/target/scripts/build.sh +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/benchmarks/vulnlab/target/templates/payment.html +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/benchmarks/vulnlab/target/trivy-results.json +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/.gitkeep +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/api-security-review/SKILL.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/api-security-review/references/inventory-template.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/api-security-review/references/output-template.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/biso-security-review/SKILL.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/biso-security-review/references/disposition.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/biso-security-review/references/orchestration.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/biso-security-review/references/output-template.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/biso-security-review/references/review-checklist.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/biso-security-review/references/risk-rating.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/cicd-security-review/SKILL.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/cicd-security-review/references/output-template.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/pci-architect/SKILL.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/pci-architect/references/control-matrix.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/pci-architect/references/output-template.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/threat-model/SKILL.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/threat-model/references/output-template.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/threat-model/references/risk-rating.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/vulnerability-manager/SKILL.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/vulnerability-manager/references/escalation.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/vulnerability-manager/references/output-template.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/vulnerability-manager/references/prioritization.md +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/finding-schema.json +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/skills.yaml +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/review.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/review_candidates.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/risk_acknowledgment.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/runtime_binding.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/safety_plan.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/section_navigation.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/stagecache.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/stateio.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/transactions.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/trust.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/tui.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/tui_progressive.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/tui_refresh.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/update_intent_review.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/update_intent_tui.py +0 -0
- {skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/vulnnormalize.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: skillctl-secure
|
|
3
|
-
Version: 0.28.
|
|
3
|
+
Version: 0.28.3
|
|
4
4
|
Summary: Package manager, trust layer, and portability layer for Agent Skills
|
|
5
5
|
Project-URL: Homepage, https://github.com/brian-scardina/skillctl
|
|
6
6
|
Project-URL: Repository, https://github.com/brian-scardina/skillctl
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.28.3"
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""Read-only finding explanations and an explicit re-audit action."""
|
|
2
|
+
from textual import work
|
|
3
|
+
from textual.binding import Binding
|
|
4
|
+
from textual.containers import Horizontal, Vertical, VerticalScroll
|
|
5
|
+
from textual.screen import ModalScreen
|
|
6
|
+
from textual.widgets import Button, Static
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
GUIDANCE = {
|
|
10
|
+
"Destructive recursive delete": ("A recursive delete can permanently remove files outside the intended workspace.", "Constrain deletion to a validated workspace path, reject empty/root paths, and require confirmation for destructive operations."),
|
|
11
|
+
"Privilege escalation / sudo usage": ("Elevated commands can modify protected system files and settings.", "Use user-owned directories and minimum permissions; document and confirm any necessary elevated operation."),
|
|
12
|
+
"SSH credential access": ("Access to SSH credentials can expose keys or allow impersonation.", "Remove private-key reads; use an SSH agent or a narrowly scoped credential integration."),
|
|
13
|
+
"Credential/environment secret reference": ("Secrets may be exposed through logs, files, or outbound requests if mishandled.", "Use a secret store or scoped environment variable, redact output, and verify that credentials only reach the intended service."),
|
|
14
|
+
"Dynamic code execution": ("Untrusted input reaching eval/exec can execute arbitrary code.", "Replace dynamic evaluation with structured parsing or allowlisted operations; trace and validate all inputs."),
|
|
15
|
+
"Outbound download command": ("Downloaded content may be untrusted or change before execution.", "Verify the source and integrity, pin versions, and inspect downloads before executing them."),
|
|
16
|
+
"Process execution": ("Commands built from untrusted input can execute unintended programs or arguments.", "Use argument arrays without a shell, validate inputs, and restrict executable paths and permissions."),
|
|
17
|
+
"External URL / network reference": ("An external reference may introduce downloads or outbound data transfers; a link alone does not prove network activity.", "Check the destination and actual use. Restrict transmitted data and validate any downloaded content; ordinary reference links may need no change."),
|
|
18
|
+
"Marks file executable": ("Executable permissions allow a downloaded or modified file to run.", "Review the file and its provenance before granting execute permission; scope permissions to the intended file."),
|
|
19
|
+
"Prompt-injection override language": ("Instructions may attempt to override the user's request or trusted instructions.", "Remove override directives, or clearly isolate quoted attack examples as untrusted data."),
|
|
20
|
+
"Potential secret exfiltration instruction": ("Instructions could cause credentials or other secrets to be sent to an external destination.", "Remove secret-transfer instructions and use scoped authentication that does not expose credential values."),
|
|
21
|
+
"Instruction to access SSH credentials": ("Instructions could lead an agent to read private SSH credentials.", "Remove instructions to read private keys and use an SSH agent or scoped authentication instead."),
|
|
22
|
+
"Potential encoded/dynamic payload handling": ("Decoded or deserialized input may conceal executable content; unsafe deserialization can run code.", "Inspect decoded content, avoid unsafe deserialization of untrusted data, and prefer validated JSON or other data-only formats."),
|
|
23
|
+
"Large file (>2 MB)": ("The heuristic scanner skipped this file, leaving its contents unreviewed.", "Remove unnecessary large assets or review the file separately with appropriate tools."),
|
|
24
|
+
"Non-text/binary or unrecognized file type": ("The heuristic scanner did not inspect the contents of this file type.", "Verify provenance and inspect with tools for that file type; remove unnecessary binaries."),
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def render_findings(audit, stale=False):
|
|
29
|
+
"""Plain text: source-controlled strings must never become Rich markup."""
|
|
30
|
+
if audit.get("error"):
|
|
31
|
+
status = f"Audit failed: {audit['error']}\nResults may be incomplete. Re-audit to retry."
|
|
32
|
+
elif not audit.get("checked_at"):
|
|
33
|
+
status = "Audit pending. Run Re-audit to inspect this skill."
|
|
34
|
+
elif stale:
|
|
35
|
+
status = "Cached audit is stale. Re-audit to check the current source."
|
|
36
|
+
else:
|
|
37
|
+
status = "Latest cached audit results."
|
|
38
|
+
findings = audit.get("findings", [])
|
|
39
|
+
lines = [status, f"\n{len(findings)} finding(s)",
|
|
40
|
+
"Heuristic matches require review; they are not confirmed vulnerabilities. Documentation examples may be benign."]
|
|
41
|
+
if not findings and audit.get("checked_at") and not audit.get("error"):
|
|
42
|
+
lines.append("\nNo heuristic findings in this cached audit.")
|
|
43
|
+
for i, finding in enumerate(sorted(findings, key=lambda f: {"HIGH": 0, "MEDIUM": 1, "LOW": 2}.get(f.get("severity"), 3)), 1):
|
|
44
|
+
message = finding.get("message", "Unknown finding")
|
|
45
|
+
risk, fix = GUIDANCE.get(message, (
|
|
46
|
+
"The scanner flagged this content; specific risk guidance is unavailable.",
|
|
47
|
+
"Inspect the referenced source and its inputs and effects, then correct unsafe behavior and re-audit."))
|
|
48
|
+
lines.extend([f"\n{i}. {finding.get('severity', 'UNKNOWN')} — {message}",
|
|
49
|
+
f"Location: {finding.get('path') or 'Unavailable'}", f"Risk: {risk}", f"Suggested fix: {fix}"])
|
|
50
|
+
lines.append("\nApply changes in the skill's maintained source, then re-audit. Managed installed copies may be overwritten by updates.")
|
|
51
|
+
return "\n".join(lines)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class FindingsScreen(ModalScreen):
|
|
55
|
+
BINDINGS = [Binding("escape", "dismiss", "Close")]
|
|
56
|
+
CSS = """
|
|
57
|
+
FindingsScreen { align: center middle; background: $background 85%; }
|
|
58
|
+
#findings-dialog { width: 90%; height: 90%; border: solid $accent; background: $surface; padding: 1 2; }
|
|
59
|
+
#findings-title { height: auto; margin-bottom: 1; text-style: bold; }
|
|
60
|
+
#findings-scroll { height: 1fr; }
|
|
61
|
+
#findings-content { height: auto; }
|
|
62
|
+
#findings-actions { height: 3; margin-top: 1; }
|
|
63
|
+
#findings-actions Button { width: 1fr; }
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def __init__(self, manager, name):
|
|
67
|
+
super().__init__()
|
|
68
|
+
self.manager = manager
|
|
69
|
+
self.skill_name = name
|
|
70
|
+
|
|
71
|
+
def compose(self):
|
|
72
|
+
with Vertical(id="findings-dialog"):
|
|
73
|
+
yield Static(f"Audit findings · {self.skill_name}", id="findings-title", markup=False)
|
|
74
|
+
with VerticalScroll(id="findings-scroll"):
|
|
75
|
+
yield Static("Loading findings…", id="findings-content", markup=False)
|
|
76
|
+
with Horizontal(id="findings-actions"):
|
|
77
|
+
yield Button("Re-audit", id="findings-audit", variant="primary")
|
|
78
|
+
yield Button("Close", id="findings-close")
|
|
79
|
+
|
|
80
|
+
def on_mount(self):
|
|
81
|
+
self.load_findings()
|
|
82
|
+
|
|
83
|
+
@work(thread=True, exclusive=True, group="finding-inspection")
|
|
84
|
+
def load_findings(self, refresh=False):
|
|
85
|
+
try:
|
|
86
|
+
spec = self.manager.get(self.skill_name)
|
|
87
|
+
if refresh:
|
|
88
|
+
self.manager.audit(spec)
|
|
89
|
+
audit = (self.manager._load_state().get(self.skill_name, {}) or {}).get("audit", {}) or {}
|
|
90
|
+
result = render_findings(audit, self.manager.audit_needed(spec))
|
|
91
|
+
except Exception as exc:
|
|
92
|
+
result = f"Unable to load audit findings: {exc}\nUse Re-audit to retry."
|
|
93
|
+
self.app.call_from_thread(self.show_result, result)
|
|
94
|
+
|
|
95
|
+
def show_result(self, result):
|
|
96
|
+
if not self.is_mounted:
|
|
97
|
+
return
|
|
98
|
+
self.query_one("#findings-content", Static).update(result)
|
|
99
|
+
self.query_one("#findings-audit", Button).disabled = False
|
|
100
|
+
|
|
101
|
+
def on_button_pressed(self, event):
|
|
102
|
+
event.stop()
|
|
103
|
+
if event.button.id == "findings-close":
|
|
104
|
+
self.dismiss()
|
|
105
|
+
elif event.button.id == "findings-audit":
|
|
106
|
+
event.button.disabled = True
|
|
107
|
+
self.query_one("#findings-content", Static).update("Auditing skill…")
|
|
108
|
+
self.load_findings(refresh=True)
|
|
@@ -96,6 +96,7 @@ def install_interaction_responsiveness(SkillCtlTUI) -> None:
|
|
|
96
96
|
self.call_from_thread(_update_audit_activity, self)
|
|
97
97
|
if not pending:
|
|
98
98
|
return
|
|
99
|
+
failed = 0
|
|
99
100
|
self.call_from_thread(_safe_worker_log, self, f"Automatic audit: {len(pending)} new/stale skill(s) queued.")
|
|
100
101
|
for spec in pending:
|
|
101
102
|
try:
|
|
@@ -106,13 +107,20 @@ def install_interaction_responsiveness(SkillCtlTUI) -> None:
|
|
|
106
107
|
low = sum(f.severity == "LOW" for f in findings)
|
|
107
108
|
self.call_from_thread(_safe_worker_log, self, f"Audited {spec.name}: HIGH:{high} MED:{medium} LOW:{low}")
|
|
108
109
|
except Exception as exc:
|
|
110
|
+
failed += 1
|
|
109
111
|
self.call_from_thread(_safe_worker_log, self, f"Automatic audit failed for {spec.name}: {exc}")
|
|
110
112
|
finally:
|
|
111
113
|
self.auto_audit_done += 1
|
|
112
114
|
self.call_from_thread(_update_audit_activity, self, spec.name)
|
|
113
115
|
self.auto_audit_running = False
|
|
114
116
|
self.call_from_thread(_update_audit_activity, self)
|
|
115
|
-
|
|
117
|
+
# Refresh once through the asynchronous snapshot worker, never per skill.
|
|
118
|
+
self.call_from_thread(self.action_refresh)
|
|
119
|
+
message = (f"Automatic audit finished: {failed}/{len(pending)} failed; see the log for details."
|
|
120
|
+
if failed else "Automatic catalog audit complete.")
|
|
121
|
+
self.call_from_thread(_safe_worker_log, self, message)
|
|
122
|
+
if failed:
|
|
123
|
+
self.call_from_thread(self.notify, message, severity="warning", timeout=10)
|
|
116
124
|
|
|
117
125
|
SkillCtlTUI._load_skill_detail = load_detail
|
|
118
126
|
SkillCtlTUI._show_detail = show_detail
|
|
@@ -187,7 +187,7 @@ class SkillCtlTUI(App):
|
|
|
187
187
|
#catalog { width: 2fr; }
|
|
188
188
|
#detail-column { width: 3fr; display: none; }
|
|
189
189
|
#detail-column.open { display: block; }
|
|
190
|
-
#btn-close-detail { height: 3; width: 100%; }
|
|
190
|
+
#btn-close-detail, #btn-findings { height: 3; width: 100%; }
|
|
191
191
|
#global-actions { height: 4; }
|
|
192
192
|
#global-actions > Horizontal { width: 1fr; height: 4; border-top: solid $panel; }
|
|
193
193
|
#detail { height: 1fr; padding: 1 2; border: solid $accent; overflow-y: auto; }
|
|
@@ -300,6 +300,7 @@ class SkillCtlTUI(App):
|
|
|
300
300
|
yield DataTable(id="table-hosts", cursor_type="row")
|
|
301
301
|
with Vertical(id="detail-column"):
|
|
302
302
|
yield Button("Close details", id="btn-close-detail", tooltip="Return to the full table (Escape)")
|
|
303
|
+
yield Button("View audit findings", id="btn-findings", tooltip="Inspect findings, risks, and suggested fixes")
|
|
303
304
|
yield Static("Select a skill", id="detail", markup=True)
|
|
304
305
|
with Horizontal(id="skill-actions"):
|
|
305
306
|
yield Button("Install", id="btn-install", variant="primary", disabled=True)
|
|
@@ -745,6 +746,7 @@ class SkillCtlTUI(App):
|
|
|
745
746
|
|
|
746
747
|
|
|
747
748
|
def _update_skill_action_buttons(self, installed: bool | None) -> None:
|
|
749
|
+
self.query_one("#btn-findings", Button).display = self.selected_kind == "skill"
|
|
748
750
|
install=self.query_one("#btn-install", Button)
|
|
749
751
|
update=self.query_one("#btn-update", Button)
|
|
750
752
|
update.label = "Update"
|
|
@@ -1244,6 +1246,12 @@ class SkillCtlTUI(App):
|
|
|
1244
1246
|
return self.manager.get(self.selected_name)
|
|
1245
1247
|
|
|
1246
1248
|
def on_button_pressed(self, event: Button.Pressed) -> None:
|
|
1249
|
+
if event.button.id == "btn-findings":
|
|
1250
|
+
event.stop()
|
|
1251
|
+
if self.selected_kind == "skill" and self.selected_name:
|
|
1252
|
+
from .findings_tui import FindingsScreen
|
|
1253
|
+
self.push_screen(FindingsScreen(self.manager, self.selected_name), lambda _: self.action_refresh())
|
|
1254
|
+
return
|
|
1247
1255
|
if event.button.id == "btn-close-detail":
|
|
1248
1256
|
event.stop()
|
|
1249
1257
|
self.action_close_detail()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.28.2"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/benchmarks/vulnlab/target/.env
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/pci-architect/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{skillctl_secure-0.28.2 → skillctl_secure-0.28.3}/skillctl/resources/custom/threat-model/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|