drydock-cli 3.0.66__tar.gz → 3.0.67__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.
Files changed (92) hide show
  1. {drydock_cli-3.0.66/drydock_cli.egg-info → drydock_cli-3.0.67}/PKG-INFO +1 -1
  2. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/rmf.py +11 -4
  3. {drydock_cli-3.0.66 → drydock_cli-3.0.67/drydock_cli.egg-info}/PKG-INFO +1 -1
  4. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock_cli.egg-info/SOURCES.txt +1 -0
  5. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/pyproject.toml +1 -1
  6. drydock_cli-3.0.67/tests/test_e2e_connected.py +70 -0
  7. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/LICENSE +0 -0
  8. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/NOTICE +0 -0
  9. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/README.md +0 -0
  10. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/__init__.py +0 -0
  11. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/__main__.py +0 -0
  12. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/agent.py +0 -0
  13. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/bash_safety.py +0 -0
  14. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/builtin_skills/__init__.py +0 -0
  15. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/builtin_skills/rmf-categorize.md +0 -0
  16. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/builtin_skills/rmf-control.md +0 -0
  17. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/builtin_skills/rmf-poam.md +0 -0
  18. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/builtin_skills/rmf-review.md +0 -0
  19. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/builtin_skills/stig-assess.md +0 -0
  20. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/cli.py +0 -0
  21. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/compaction.py +0 -0
  22. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/config.py +0 -0
  23. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/detect.py +0 -0
  24. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/extract.py +0 -0
  25. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/gittools.py +0 -0
  26. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/graphrag.py +0 -0
  27. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/guards.py +0 -0
  28. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/loop_detect.py +0 -0
  29. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/mcp.py +0 -0
  30. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/providers.py +0 -0
  31. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/rmf_graph.py +0 -0
  32. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/skills.py +0 -0
  33. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/stig.py +0 -0
  34. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/tool_registry.py +0 -0
  35. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/tools/__init__.py +0 -0
  36. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/tui/__init__.py +0 -0
  37. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/tui/app.py +0 -0
  38. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/tui/approval.py +0 -0
  39. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/tui/messages.py +0 -0
  40. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/tui/widgets.py +0 -0
  41. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/tuning.py +0 -0
  42. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock/web.py +0 -0
  43. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock_cli.egg-info/dependency_links.txt +0 -0
  44. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock_cli.egg-info/entry_points.txt +0 -0
  45. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock_cli.egg-info/requires.txt +0 -0
  46. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/drydock_cli.egg-info/top_level.txt +0 -0
  47. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/setup.cfg +0 -0
  48. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_approval.py +0 -0
  49. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_back_command.py +0 -0
  50. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_bash_output_bounding.py +0 -0
  51. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_bash_process_group.py +0 -0
  52. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_bash_safety.py +0 -0
  53. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_bash_timeout_network.py +0 -0
  54. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_cli_agents.py +0 -0
  55. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_compact_command.py +0 -0
  56. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_compaction.py +0 -0
  57. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_config.py +0 -0
  58. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_config_migration.py +0 -0
  59. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_context_limit_config.py +0 -0
  60. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_detect.py +0 -0
  61. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_dispatch.py +0 -0
  62. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_empty_response.py +0 -0
  63. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_extract.py +0 -0
  64. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_failure_loop.py +0 -0
  65. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_first_run_setup.py +0 -0
  66. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_gittools.py +0 -0
  67. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_graphrag.py +0 -0
  68. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_guards_and_tools.py +0 -0
  69. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_hallucinated_tools.py +0 -0
  70. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_leaked_tool_call.py +0 -0
  71. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_loop_detect.py +0 -0
  72. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_mcp.py +0 -0
  73. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_oneshot_unreachable.py +0 -0
  74. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_plan_autocontinue.py +0 -0
  75. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_providers_unreachable.py +0 -0
  76. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_read_index.py +0 -0
  77. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_rmf.py +0 -0
  78. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_rmf_graph.py +0 -0
  79. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_runaway_repetition.py +0 -0
  80. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_skills.py +0 -0
  81. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_stig.py +0 -0
  82. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_stop.py +0 -0
  83. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_streaming_newlines.py +0 -0
  84. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_subagent.py +0 -0
  85. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_system_prompt_help.py +0 -0
  86. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_todo.py +0 -0
  87. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_tool_arg_parsing.py +0 -0
  88. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_tools_undo.py +0 -0
  89. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_tui.py +0 -0
  90. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_tuning.py +0 -0
  91. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_vision_input.py +0 -0
  92. {drydock_cli-3.0.66 → drydock_cli-3.0.67}/tests/test_web_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.0.66
3
+ Version: 3.0.67
4
4
  Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
5
5
  Author: Frank Bobe III
6
6
  License-Expression: Apache-2.0
@@ -108,16 +108,23 @@ def rmf_dir(cwd: str) -> Path:
108
108
 
109
109
 
110
110
  def bootstrap(cwd: str, *, families: list[str] | None = None,
111
- source: str | Path | None = None) -> dict:
111
+ source: str | Path | None = None, refresh: bool = False) -> dict:
112
112
  """Fetch (if needed) + flatten the 800-53 catalog into <cwd>/.drydock/rmf and
113
113
  ingest it into the GraphRAG KB. Returns {families, controls_docs, **kb_stats}.
114
- `source` reuses an already-downloaded catalog JSON (offline)."""
114
+ `source` reuses an already-downloaded catalog JSON (offline). `refresh` pulls
115
+ the latest from upstream, but falls back to the cached catalog if upstream is
116
+ unreachable — so a network blip never stalls an assessment (PRD §4)."""
115
117
  from drydock import graphrag
116
118
 
117
119
  base = rmf_dir(cwd)
118
120
  cat_path = Path(source) if source else base / "catalog.json"
119
- if not cat_path.exists():
120
- fetch_catalog(cat_path)
121
+ if source is None and (refresh or not cat_path.exists()):
122
+ try:
123
+ fetch_catalog(cat_path)
124
+ except Exception: # noqa: BLE001 — any network/HTTP failure
125
+ if not cat_path.exists():
126
+ raise # nothing cached to fall back to
127
+ # else: keep using the cached catalog
121
128
  catalog = json.loads(Path(cat_path).read_text("utf-8"))
122
129
  docs = catalog_to_family_docs(catalog, base / "800-53", families)
123
130
  store = graphrag.default_store_path(cwd)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.0.66
3
+ Version: 3.0.67
4
4
  Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
5
5
  Author: Frank Bobe III
6
6
  License-Expression: Apache-2.0
@@ -56,6 +56,7 @@ tests/test_config_migration.py
56
56
  tests/test_context_limit_config.py
57
57
  tests/test_detect.py
58
58
  tests/test_dispatch.py
59
+ tests/test_e2e_connected.py
59
60
  tests/test_empty_response.py
60
61
  tests/test_extract.py
61
62
  tests/test_failure_loop.py
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
  # PyPI distribution name is drydock-cli (the established install name, continued
8
8
  # from the retired v2 fork); the import package + CLI command stay `drydock`.
9
9
  name = "drydock-cli"
10
- version = "3.0.66"
10
+ version = "3.0.67"
11
11
  description = "Drydock — a local, provider-agnostic terminal coding agent for local LLMs"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.11"
@@ -0,0 +1,70 @@
1
+ """Connected E2E tests (RMF E2E PRD). The DETERMINISTIC + integration parts:
2
+ schema fidelity, and network-resilience fallback. The LIVE upstream fetch is
3
+ opt-in (set DRYDOCK_E2E_NETWORK=1) so the normal suite stays fast + offline-safe.
4
+ Model-accuracy suites (assessment/remediation correctness) are verified hands-on
5
+ in the TUI, not here (see the operator's TUI-only rule)."""
6
+ from __future__ import annotations
7
+
8
+ import json
9
+ import os
10
+ import xml.etree.ElementTree as ET
11
+
12
+ import pytest
13
+
14
+ from drydock import rmf, rmf_graph, stig
15
+
16
+ _CAT = {"catalog": {"groups": [{"id": "ac", "title": "Access Control", "controls": [
17
+ {"id": "ac-2", "title": "Account Management",
18
+ "parts": [{"name": "statement", "prose": "Manage accounts."}]}]}]}}
19
+
20
+
21
+ def test_network_resilience_falls_back_to_cache(tmp_path, monkeypatch):
22
+ # Seed a cached catalog, then make upstream fetch fail on refresh.
23
+ base = rmf.rmf_dir(str(tmp_path)); base.mkdir(parents=True)
24
+ (base / "catalog.json").write_text(json.dumps(_CAT))
25
+
26
+ def boom(*a, **k):
27
+ raise OSError("upstream unreachable")
28
+ monkeypatch.setattr(rmf, "fetch_catalog", boom)
29
+ # refresh=True tries upstream, fails, but falls back to the cache → no crash
30
+ stats = rmf.bootstrap(str(tmp_path), refresh=True)
31
+ assert stats["family_docs"] == 1 and stats["chunks"] >= 1
32
+
33
+
34
+ def test_first_bootstrap_offline_with_no_cache_raises(tmp_path, monkeypatch):
35
+ monkeypatch.setattr(rmf, "fetch_catalog", lambda *a, **k: (_ for _ in ()).throw(OSError("down")))
36
+ with pytest.raises(OSError):
37
+ rmf.bootstrap(str(tmp_path)) # nothing cached to fall back to
38
+
39
+
40
+ def test_ckl_regenerates_wellformed_and_status_enum(tmp_path):
41
+ p = tmp_path / "r.ckl"
42
+ p.write_text('<?xml version="1.0"?><CHECKLIST><ASSET><HOST_NAME>h</HOST_NAME></ASSET>'
43
+ '<STIGS><iSTIG><STIG_INFO></STIG_INFO><VULN>'
44
+ '<STIG_DATA><VULN_ATTRIBUTE>Vuln_Num</VULN_ATTRIBUTE><ATTRIBUTE_DATA>V-1</ATTRIBUTE_DATA></STIG_DATA>'
45
+ '<STIG_DATA><VULN_ATTRIBUTE>Rule_ID</VULN_ATTRIBUTE><ATTRIBUTE_DATA>SV-1</ATTRIBUTE_DATA></STIG_DATA>'
46
+ '<STATUS>Not_Reviewed</STATUS><FINDING_DETAILS></FINDING_DETAILS><COMMENTS></COMMENTS>'
47
+ '</VULN></iSTIG></STIGS></CHECKLIST>')
48
+ cl = stig.load(p); cl.update("V-1", status="open", finding_details="x"); cl.save(p)
49
+ root = ET.parse(p).getroot() # re-parses = well-formed
50
+ statuses = [v.findtext("STATUS") for v in root.iter("VULN")]
51
+ valid = {"Open", "NotAFinding", "Not_Applicable", "Not_Reviewed"}
52
+ assert all(s in valid for s in statuses) # DISA status enum preserved
53
+ assert root.find(".//VULN/STIG_DATA/ATTRIBUTE_DATA").text == "V-1" # data fidelity
54
+
55
+
56
+ def test_graph_relationship_semantics(tmp_path):
57
+ # Suite A semantics: COMPONENT -IMPLEMENTS-> CONTROL resolves.
58
+ g = rmf_graph.build_from_catalog(_CAT)
59
+ g.add_edge(rmf_graph.component_id("srv"), "IMPLEMENTS", rmf_graph.control_id("ac-2"))
60
+ assert rmf_graph.control_id("ac-2") in g.neighbors(rmf_graph.component_id("srv"), "IMPLEMENTS")
61
+
62
+
63
+ @pytest.mark.skipif(os.environ.get("DRYDOCK_E2E_NETWORK") != "1",
64
+ reason="live network test; set DRYDOCK_E2E_NETWORK=1 to run")
65
+ def test_live_nist_catalog_fetch_and_parse(tmp_path):
66
+ # Suite A: pull the REAL NIST 800-53 catalog from upstream and parse it.
67
+ cat = rmf.fetch_catalog(tmp_path / "cat.json")
68
+ catalog = json.loads(cat.read_text())
69
+ docs = rmf.catalog_to_family_docs(catalog, tmp_path / "out", families=["ac"])
70
+ assert docs and "AC-2" in docs[0].read_text()
File without changes
File without changes
File without changes
File without changes