unvibecode 0.3.0__py3-none-any.whl
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.
- shipreadyv2/SOURCE_MANIFEST.json +27 -0
- shipreadyv2/__init__.py +3 -0
- shipreadyv2/__main__.py +5 -0
- shipreadyv2/cli.py +204 -0
- shipreadyv2/credentials.py +178 -0
- shipreadyv2/customer_runner.py +2457 -0
- shipreadyv2/engine_sources/00a_shipreadyv2_fast_lane_v11_api_context_bundle.py +5862 -0
- shipreadyv2/engine_sources/01_shipreadyv2_merged_graph_pipeline_5chunks.py +4703 -0
- shipreadyv2/engine_sources/02_shipreadyv2_prepare_pass1_inputs.py +996 -0
- shipreadyv2/engine_sources/03_shipreadyv2_pass1_full_runner.py +1666 -0
- shipreadyv2/engine_sources/04_shipreadyv2_business_path_compiler.py +3444 -0
- shipreadyv2/engine_sources/05_shipreadyv2_critical_business_insight_selector_v4.py +1756 -0
- shipreadyv2/engine_sources/06_shipreadyv2_step4_v2_with_v4_inputs.py +2155 -0
- shipreadyv2/engine_sources/__init__.py +2 -0
- shipreadyv2/engine_sources/agent_knowledge_graph.db +0 -0
- shipreadyv2/engine_sources/archetype_taxonomy.yaml +2127 -0
- shipreadyv2/engine_sources/archetype_taxonomy_pass1_compact.yaml +1922 -0
- shipreadyv2/engine_sources/build_pass1_compact_taxonomy.py +330 -0
- shipreadyv2/engine_sources/generate_combinedjson.py +184 -0
- shipreadyv2/engine_sources/normalized_business_path.schema.json +840 -0
- shipreadyv2/engine_sources/shipready_business_insight_implementation_plan_v2.md +1006 -0
- shipreadyv2/engine_sources/universal_insight_rules.yaml +875 -0
- unvibecode-0.3.0.dist-info/METADATA +133 -0
- unvibecode-0.3.0.dist-info/RECORD +27 -0
- unvibecode-0.3.0.dist-info/WHEEL +5 -0
- unvibecode-0.3.0.dist-info/entry_points.txt +2 -0
- unvibecode-0.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": "shipreadyv2.exact_source_manifest.v2",
|
|
3
|
+
"package_version": "0.3.0",
|
|
4
|
+
"engine_baseline_version": "0.2.1",
|
|
5
|
+
"engine_changes_from_baseline": [],
|
|
6
|
+
"hash_mode": "LF-normalized SHA-256 for text; raw SHA-256 for binary",
|
|
7
|
+
"customer_runner_source": "shipreadyv2_customer_mvp_runner_v9.py",
|
|
8
|
+
"engine_source": "shipreadyv2_fresh_source.zip plus universal_insight_rules.yaml",
|
|
9
|
+
"source_files": {
|
|
10
|
+
"customer_runner.py": "6a0593de05be1a460c0375a431331fb115d6426c507a185a087c801a78055c1d",
|
|
11
|
+
"engine_sources/00a_shipreadyv2_fast_lane_v11_api_context_bundle.py": "1eac10db5403bb470929da4b52eaafb88dbce6b5919492016754e227680e7c3e",
|
|
12
|
+
"engine_sources/01_shipreadyv2_merged_graph_pipeline_5chunks.py": "697f7dda0a65a582939bae75b16d601342fd547adeda1a209778f60903a494a2",
|
|
13
|
+
"engine_sources/02_shipreadyv2_prepare_pass1_inputs.py": "cb5bb27a6d923341e55b2b121e128bcce66edf04937cc3b18e31d5f3989fe891",
|
|
14
|
+
"engine_sources/03_shipreadyv2_pass1_full_runner.py": "40e5a0afd70e55110c1784f5e29332a910fad3b03fe3030492633277ff93caba",
|
|
15
|
+
"engine_sources/04_shipreadyv2_business_path_compiler.py": "7ed142e07cb37b1f90084837b7cb45f63f2718826f121b834c5e1a5a57ffab94",
|
|
16
|
+
"engine_sources/05_shipreadyv2_critical_business_insight_selector_v4.py": "e770c8cd21a06a7a02d8e8f9e8c6f7bedb1a5b7be96fdb6ba646e740f006a011",
|
|
17
|
+
"engine_sources/06_shipreadyv2_step4_v2_with_v4_inputs.py": "6dbc77b72e0066f9fcfb7e5d92026bb6b54b77a8eed687a94971c4d9ab6160c2",
|
|
18
|
+
"engine_sources/agent_knowledge_graph.db": "db362f684eb4d9e43827400f4e11f1dfd7cbfffa5fd481c105cd9d3f14d9f8b2",
|
|
19
|
+
"engine_sources/archetype_taxonomy.yaml": "55e98bdace2af1a1dbe6a73315e651383f9f2ca265a3ad5ca262dbd8acbf1f5f",
|
|
20
|
+
"engine_sources/archetype_taxonomy_pass1_compact.yaml": "93452175b35bd74bc9043766324c8442607e920a70548115c32a0b09a33673e3",
|
|
21
|
+
"engine_sources/build_pass1_compact_taxonomy.py": "5d8692214509c80dddeb2e2eee0d6f80f172d8150b9640db27dbeb07dec69769",
|
|
22
|
+
"engine_sources/generate_combinedjson.py": "1c2ffbb4ec9d40b9b4304abc2848943a69424d3087125993733a1b57064f5267",
|
|
23
|
+
"engine_sources/normalized_business_path.schema.json": "5d408b2cce353ab6ef4b37a0686330ff5610c6d7aaf4bc37fdf9b0aa1fc665cd",
|
|
24
|
+
"engine_sources/shipready_business_insight_implementation_plan_v2.md": "210cc34f9a28c7e4acc4ba39a164f8d78ce5c97b99fb9f9beff308db2bda7eac",
|
|
25
|
+
"engine_sources/universal_insight_rules.yaml": "4aa10f8c581100190c24365fa4188862c49738403db36c6c298ba15c54067ab7"
|
|
26
|
+
}
|
|
27
|
+
}
|
shipreadyv2/__init__.py
ADDED
shipreadyv2/__main__.py
ADDED
shipreadyv2/cli.py
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"""Customer-facing command adapter for the preserved ShipReadyV2 workflow."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import contextlib
|
|
7
|
+
import getpass
|
|
8
|
+
import os
|
|
9
|
+
import shutil
|
|
10
|
+
import tempfile
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Iterator, Optional, Sequence
|
|
13
|
+
|
|
14
|
+
from . import __version__
|
|
15
|
+
from . import customer_runner
|
|
16
|
+
from . import credentials
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def bundled_engine_root() -> Path:
|
|
20
|
+
"""Return the installed directory containing the preserved engine files."""
|
|
21
|
+
return Path(__file__).resolve().parent / "engine_sources"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def default_runs_root() -> Path:
|
|
25
|
+
"""Keep customer runs outside the installed Python package."""
|
|
26
|
+
return Path.cwd() / "shipready_results"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@contextlib.contextmanager
|
|
30
|
+
def prepared_runtime_engine(access_key: str) -> Iterator[Path]:
|
|
31
|
+
"""Provide the preserved scripts with a private hosted-service environment.
|
|
32
|
+
|
|
33
|
+
Steps 03 and 06 require an engine-root .env file before they read the
|
|
34
|
+
SDK credential. The value supplied here is a ShipReady customer credential,
|
|
35
|
+
and OPENAI_BASE_URL directs the unmodified OpenAI SDK calls to ShipReady's
|
|
36
|
+
hosted gateway. The customer never supplies an OpenAI API key.
|
|
37
|
+
|
|
38
|
+
Installed package directories may be read-only, so the adapter copies the
|
|
39
|
+
preserved engine into a private temporary directory for the duration of the
|
|
40
|
+
review. The directory and its temporary .env file are removed afterward.
|
|
41
|
+
"""
|
|
42
|
+
access_key = credentials.normalize_access_key(access_key)
|
|
43
|
+
if "\r" in access_key or "\n" in access_key:
|
|
44
|
+
raise customer_runner.CustomerRunError(
|
|
45
|
+
"The ShipReady access key contains an invalid line break"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
hosted_environment = {
|
|
49
|
+
"OPENAI_API_KEY": access_key,
|
|
50
|
+
"OPENAI_BASE_URL": credentials.api_base_url(),
|
|
51
|
+
}
|
|
52
|
+
previous_environment = {
|
|
53
|
+
name: os.environ.get(name)
|
|
54
|
+
for name in hosted_environment
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
with tempfile.TemporaryDirectory(prefix="shipreadyv2-engine-") as temporary:
|
|
58
|
+
runtime_root = Path(temporary) / "engine"
|
|
59
|
+
shutil.copytree(
|
|
60
|
+
bundled_engine_root(),
|
|
61
|
+
runtime_root,
|
|
62
|
+
ignore=shutil.ignore_patterns("__pycache__", "*.pyc"),
|
|
63
|
+
)
|
|
64
|
+
(runtime_root / ".env").write_text(
|
|
65
|
+
(
|
|
66
|
+
f"OPENAI_API_KEY={access_key}\n"
|
|
67
|
+
f"OPENAI_BASE_URL={credentials.api_base_url()}\n"
|
|
68
|
+
),
|
|
69
|
+
encoding="utf-8",
|
|
70
|
+
)
|
|
71
|
+
try:
|
|
72
|
+
os.environ.update(hosted_environment)
|
|
73
|
+
yield runtime_root
|
|
74
|
+
finally:
|
|
75
|
+
for name, previous_value in previous_environment.items():
|
|
76
|
+
if previous_value is None:
|
|
77
|
+
os.environ.pop(name, None)
|
|
78
|
+
else:
|
|
79
|
+
os.environ[name] = previous_value
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
83
|
+
parser = argparse.ArgumentParser(
|
|
84
|
+
prog="shipready",
|
|
85
|
+
description=(
|
|
86
|
+
"Prepare a Connected Code Map for LLMs and, when repository size "
|
|
87
|
+
"permits, a Business Workflow & Risk Review."
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
parser.add_argument(
|
|
91
|
+
"--version",
|
|
92
|
+
action="version",
|
|
93
|
+
version=f"%(prog)s {__version__}",
|
|
94
|
+
)
|
|
95
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
96
|
+
|
|
97
|
+
subparsers.add_parser(
|
|
98
|
+
"activate",
|
|
99
|
+
help="Securely activate ShipReady on this computer",
|
|
100
|
+
)
|
|
101
|
+
subparsers.add_parser(
|
|
102
|
+
"deactivate",
|
|
103
|
+
help="Remove the stored ShipReady access key",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
review = subparsers.add_parser("review", help="Review a source repository")
|
|
107
|
+
review.add_argument("--repository", required=True)
|
|
108
|
+
review.add_argument(
|
|
109
|
+
"--runs-root",
|
|
110
|
+
default=str(default_runs_root()),
|
|
111
|
+
help=(
|
|
112
|
+
"Folder for repository-review runs "
|
|
113
|
+
"(default: ./shipready_results)"
|
|
114
|
+
),
|
|
115
|
+
)
|
|
116
|
+
review.add_argument(
|
|
117
|
+
"--large-repo-token-limit",
|
|
118
|
+
type=int,
|
|
119
|
+
default=customer_runner.DEFAULT_LARGE_REPOSITORY_TOKEN_LIMIT,
|
|
120
|
+
help=(
|
|
121
|
+
"Prepare only the Connected Code Map above this approximate token "
|
|
122
|
+
"count (default: 2000000)"
|
|
123
|
+
),
|
|
124
|
+
)
|
|
125
|
+
review.add_argument(
|
|
126
|
+
"--no-open-browser",
|
|
127
|
+
action="store_true",
|
|
128
|
+
help="Create customer HTML reports without opening browser tabs",
|
|
129
|
+
)
|
|
130
|
+
return parser
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
134
|
+
parser = build_parser()
|
|
135
|
+
args = parser.parse_args(argv)
|
|
136
|
+
|
|
137
|
+
if args.command == "activate":
|
|
138
|
+
try:
|
|
139
|
+
access_key = credentials.normalize_access_key(
|
|
140
|
+
getpass.getpass("Paste your ShipReady access key: ")
|
|
141
|
+
)
|
|
142
|
+
verification = credentials.verify_access_key(access_key)
|
|
143
|
+
if not verification.valid:
|
|
144
|
+
print(f"[STOPPED] {verification.message}")
|
|
145
|
+
return 2
|
|
146
|
+
credentials.store_access_key(access_key)
|
|
147
|
+
except (credentials.CredentialError, KeyboardInterrupt, EOFError) as exc:
|
|
148
|
+
message = str(exc) or "Activation was cancelled."
|
|
149
|
+
print(f"[STOPPED] {message}")
|
|
150
|
+
return 2
|
|
151
|
+
print("ShipReady access is ready on this computer.")
|
|
152
|
+
return 0
|
|
153
|
+
|
|
154
|
+
if args.command == "deactivate":
|
|
155
|
+
try:
|
|
156
|
+
removed = credentials.delete_access_key()
|
|
157
|
+
except credentials.CredentialError as exc:
|
|
158
|
+
print(f"[STOPPED] {exc}")
|
|
159
|
+
return 2
|
|
160
|
+
if removed:
|
|
161
|
+
print("ShipReady access was removed from this computer.")
|
|
162
|
+
else:
|
|
163
|
+
print("ShipReady was not activated on this computer.")
|
|
164
|
+
return 0
|
|
165
|
+
|
|
166
|
+
if args.command != "review":
|
|
167
|
+
parser.error("A supported command is required")
|
|
168
|
+
if args.large_repo_token_limit <= 0:
|
|
169
|
+
parser.error("--large-repo-token-limit must be greater than zero")
|
|
170
|
+
|
|
171
|
+
try:
|
|
172
|
+
access_key = credentials.load_access_key()
|
|
173
|
+
if not access_key:
|
|
174
|
+
raise credentials.CredentialError(
|
|
175
|
+
"ShipReady is not activated. Run: shipready activate"
|
|
176
|
+
)
|
|
177
|
+
except credentials.CredentialError as exc:
|
|
178
|
+
print(f"[STOPPED] {exc}")
|
|
179
|
+
return 2
|
|
180
|
+
|
|
181
|
+
try:
|
|
182
|
+
with prepared_runtime_engine(access_key) as engine_root:
|
|
183
|
+
runner_args = [
|
|
184
|
+
"start",
|
|
185
|
+
"--repository",
|
|
186
|
+
str(Path(args.repository).expanduser()),
|
|
187
|
+
"--engine-root",
|
|
188
|
+
str(engine_root),
|
|
189
|
+
"--runs-root",
|
|
190
|
+
str(Path(args.runs_root).expanduser()),
|
|
191
|
+
"--large-repo-token-limit",
|
|
192
|
+
str(args.large_repo_token_limit),
|
|
193
|
+
]
|
|
194
|
+
if args.no_open_browser:
|
|
195
|
+
runner_args.append("--no-open-browser")
|
|
196
|
+
|
|
197
|
+
return customer_runner.main(runner_args)
|
|
198
|
+
except customer_runner.CustomerRunError as exc:
|
|
199
|
+
print(f"[STOPPED] {exc}")
|
|
200
|
+
return 2
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
if __name__ == "__main__":
|
|
204
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""ShipReady hosted-service credential storage and verification."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import urllib.error
|
|
8
|
+
import urllib.request
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
DEFAULT_API_BASE_URL = "https://shipready-api.alphashots.ai/v1"
|
|
14
|
+
KEYRING_SERVICE = "ShipReady"
|
|
15
|
+
KEYRING_USERNAME = "customer-access-key"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CredentialError(RuntimeError):
|
|
19
|
+
"""Raised when a ShipReady access credential cannot be used safely."""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(frozen=True)
|
|
23
|
+
class VerificationResult:
|
|
24
|
+
valid: bool
|
|
25
|
+
message: str
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def api_base_url() -> str:
|
|
29
|
+
"""Return the fixed production URL, with a test-only environment override."""
|
|
30
|
+
|
|
31
|
+
value = (
|
|
32
|
+
os.getenv("SHIPREADY_API_BASE_URL")
|
|
33
|
+
or DEFAULT_API_BASE_URL
|
|
34
|
+
).strip().rstrip("/")
|
|
35
|
+
if not value.startswith("https://"):
|
|
36
|
+
raise CredentialError("The ShipReady service URL must use HTTPS.")
|
|
37
|
+
return value
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def normalize_access_key(value: str) -> str:
|
|
41
|
+
"""Validate a customer key without exposing it in an error."""
|
|
42
|
+
|
|
43
|
+
key = value.strip().strip("\"'").strip()
|
|
44
|
+
if not key:
|
|
45
|
+
raise CredentialError("A ShipReady access key is required.")
|
|
46
|
+
if "\r" in key or "\n" in key or any(character.isspace() for character in key):
|
|
47
|
+
raise CredentialError("The ShipReady access key contains invalid whitespace.")
|
|
48
|
+
try:
|
|
49
|
+
key.encode("ascii")
|
|
50
|
+
except UnicodeEncodeError as exc:
|
|
51
|
+
raise CredentialError(
|
|
52
|
+
"The ShipReady access key contains an invalid character."
|
|
53
|
+
) from exc
|
|
54
|
+
if len(key) < 24:
|
|
55
|
+
raise CredentialError("The ShipReady access key is not valid.")
|
|
56
|
+
return key
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _keyring_module():
|
|
60
|
+
try:
|
|
61
|
+
import keyring # type: ignore
|
|
62
|
+
except ImportError as exc:
|
|
63
|
+
raise CredentialError(
|
|
64
|
+
"Secure credential storage is unavailable. Reinstall ShipReady."
|
|
65
|
+
) from exc
|
|
66
|
+
return keyring
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def store_access_key(value: str) -> None:
|
|
70
|
+
"""Store the key in the operating system credential manager."""
|
|
71
|
+
|
|
72
|
+
key = normalize_access_key(value)
|
|
73
|
+
try:
|
|
74
|
+
_keyring_module().set_password(KEYRING_SERVICE, KEYRING_USERNAME, key)
|
|
75
|
+
except Exception as exc:
|
|
76
|
+
raise CredentialError(
|
|
77
|
+
"The operating system credential manager could not store the "
|
|
78
|
+
"ShipReady access key."
|
|
79
|
+
) from exc
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def delete_access_key() -> bool:
|
|
83
|
+
"""Delete the stored key, returning False when no stored key exists."""
|
|
84
|
+
|
|
85
|
+
keyring = _keyring_module()
|
|
86
|
+
try:
|
|
87
|
+
existing = keyring.get_password(KEYRING_SERVICE, KEYRING_USERNAME)
|
|
88
|
+
if not existing:
|
|
89
|
+
return False
|
|
90
|
+
keyring.delete_password(KEYRING_SERVICE, KEYRING_USERNAME)
|
|
91
|
+
except Exception as exc:
|
|
92
|
+
raise CredentialError(
|
|
93
|
+
"The operating system credential manager could not remove the "
|
|
94
|
+
"ShipReady access key."
|
|
95
|
+
) from exc
|
|
96
|
+
return True
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def load_access_key() -> Optional[str]:
|
|
100
|
+
"""Prefer an automation environment variable, then secure local storage."""
|
|
101
|
+
|
|
102
|
+
environment_key = (os.getenv("SHIPREADY_ACCESS_KEY") or "").strip()
|
|
103
|
+
if environment_key:
|
|
104
|
+
return normalize_access_key(environment_key)
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
stored = _keyring_module().get_password(
|
|
108
|
+
KEYRING_SERVICE,
|
|
109
|
+
KEYRING_USERNAME,
|
|
110
|
+
)
|
|
111
|
+
except CredentialError:
|
|
112
|
+
raise
|
|
113
|
+
except Exception as exc:
|
|
114
|
+
raise CredentialError(
|
|
115
|
+
"The operating system credential manager could not read the "
|
|
116
|
+
"ShipReady access key."
|
|
117
|
+
) from exc
|
|
118
|
+
if not stored:
|
|
119
|
+
return None
|
|
120
|
+
return normalize_access_key(stored)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def verify_access_key(value: str, timeout_seconds: float = 20.0) -> VerificationResult:
|
|
124
|
+
"""Verify authentication without sending repository code or invoking a model.
|
|
125
|
+
|
|
126
|
+
The gateway authenticates before validating the request body. Therefore an
|
|
127
|
+
empty JSON request returns 400 for a valid key and 401/403 for an invalid key.
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
key = normalize_access_key(value)
|
|
131
|
+
request = urllib.request.Request(
|
|
132
|
+
f"{api_base_url()}/responses",
|
|
133
|
+
data=b"{}",
|
|
134
|
+
headers={
|
|
135
|
+
"Authorization": f"Bearer {key}",
|
|
136
|
+
"Content-Type": "application/json",
|
|
137
|
+
"User-Agent": "ShipReady-Activation/0.3",
|
|
138
|
+
},
|
|
139
|
+
method="POST",
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
with urllib.request.urlopen(request, timeout=timeout_seconds) as response:
|
|
144
|
+
status = int(response.status)
|
|
145
|
+
except urllib.error.HTTPError as exc:
|
|
146
|
+
status = int(exc.code)
|
|
147
|
+
try:
|
|
148
|
+
payload = json.loads(exc.read().decode("utf-8", errors="replace"))
|
|
149
|
+
except Exception:
|
|
150
|
+
payload = {}
|
|
151
|
+
if status in {401, 403}:
|
|
152
|
+
message = (
|
|
153
|
+
payload.get("error", {}).get("message")
|
|
154
|
+
if isinstance(payload, dict)
|
|
155
|
+
else None
|
|
156
|
+
)
|
|
157
|
+
return VerificationResult(
|
|
158
|
+
False,
|
|
159
|
+
str(message or "The ShipReady access key was rejected."),
|
|
160
|
+
)
|
|
161
|
+
if status == 400:
|
|
162
|
+
return VerificationResult(True, "ShipReady access verified.")
|
|
163
|
+
return VerificationResult(
|
|
164
|
+
False,
|
|
165
|
+
f"The ShipReady service returned HTTP {status}.",
|
|
166
|
+
)
|
|
167
|
+
except (urllib.error.URLError, TimeoutError) as exc:
|
|
168
|
+
raise CredentialError(
|
|
169
|
+
"The ShipReady service could not be reached. Check the internet "
|
|
170
|
+
"connection and try again."
|
|
171
|
+
) from exc
|
|
172
|
+
|
|
173
|
+
if 200 <= status < 300:
|
|
174
|
+
return VerificationResult(True, "ShipReady access verified.")
|
|
175
|
+
return VerificationResult(
|
|
176
|
+
False,
|
|
177
|
+
f"The ShipReady service returned HTTP {status}.",
|
|
178
|
+
)
|