mostlyright-data 0.19.7__tar.gz → 0.20.0__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.
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/PKG-INFO +3 -3
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/README.md +1 -1
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/pyproject.toml +2 -2
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/__init__.py +1 -1
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/download.py +9 -1
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/runs.py +32 -1
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/stream.py +10 -2
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/credential_store.py +43 -2
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/credentials.py +11 -7
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/login.py +2 -1
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/remediation.py +14 -1
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/.gitignore +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/scripts/hatch_build.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/skills/mr-data-build/SKILL.md +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/skills/mr-data-build/agents/openai.yaml +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/skills/mr-data-build/scripts/write_research_notebook.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/__init__.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/canonical.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/formats.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/hosted_crawler_protocol.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/key_seam.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/page_coverage.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/part_check_evidence.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/session_probes.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/skill_assets.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/table_manifest.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/acquire.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/acquire_cancel.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/activity.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/approvals.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/categories.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/commands.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/dataset-categories-v1.json +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/narrative.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/parity.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/probe.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/progress_vocabulary.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/propose.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/recipe.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/research.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/router.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/session.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/stream_venue.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/transport.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/user_agent.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_artifacts.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_catalog.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_connections.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_dataset_covers.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_datasets.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_handoff.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_narrative.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_query.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_runs.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_secrets.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_stream.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_tables.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/vocabulary.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/__init__.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/attendance.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/clarification.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/cloud_auth.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/commands/__init__.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/commands/auth.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/commands/clarify.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/commands/login.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/commands/whoami.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/credential_native.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/path_kind.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/plain_file.py +0 -0
- {mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/render.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mostlyright-data
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.20.0
|
|
4
4
|
Summary: Mostly Right hosted CLI for reviewed datasets
|
|
5
5
|
Project-URL: Homepage, https://mostlyright.md/
|
|
6
6
|
Project-URL: Documentation, https://mostlyright.md/docs/guides/cli/
|
|
7
|
-
Requires-Python: >=3.
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
8
|
Provides-Extra: build
|
|
9
9
|
Requires-Dist: hatchling==1.28.0; extra == 'build'
|
|
10
10
|
Requires-Dist: uv-build==0.11.3; extra == 'build'
|
|
@@ -22,7 +22,7 @@ they finish.
|
|
|
22
22
|
|
|
23
23
|
## Requirements
|
|
24
24
|
|
|
25
|
-
Use CPython 3.
|
|
25
|
+
Use CPython 3.11 or newer.
|
|
26
26
|
|
|
27
27
|
## Install
|
|
28
28
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mostlyright-data"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.20.0"
|
|
4
4
|
description = "Mostly Right hosted CLI for reviewed datasets"
|
|
5
5
|
readme = "README.md"
|
|
6
|
-
requires-python = ">=3.
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
7
|
# The published Harness package is a pure-Python, stdlib-only hosted client. Dataset execution,
|
|
8
8
|
# native readers, and worker publication live in Mostly Right Studio.
|
|
9
9
|
dependencies = []
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/__init__.py
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""The pure-Python hosted lane: auth, submit, stream, download, receipts.
|
|
2
2
|
|
|
3
|
-
Every module in this package is importable on a bare CPython 3.
|
|
3
|
+
Every module in this package is importable on a bare CPython 3.11 with no compiled extension in
|
|
4
4
|
site-packages. That is the whole contract of the package and it is asserted rather than intended:
|
|
5
5
|
:mod:`tests.test_thin_profile` installs the base distribution into a fresh environment, refuses any
|
|
6
6
|
``.so``/``.pyd``/``.dylib`` it finds, and imports the command router there.
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/download.py
RENAMED
|
@@ -88,7 +88,15 @@ class DownloadedArtifact:
|
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
def _required_headers(session: Mapping[str, Any]) -> dict[str, str]:
|
|
91
|
-
"""The headers
|
|
91
|
+
"""The headers Studio signed, replayed exactly as it stated them.
|
|
92
|
+
|
|
93
|
+
Omitting one, or altering a value, is what invalidates the signature; this builds the outgoing
|
|
94
|
+
set from the session and from nothing else, so neither can happen here. It is NOT an exact
|
|
95
|
+
header set for the request as a whole -- :class:`~mostlyright.data_harness.thin.transport.
|
|
96
|
+
UrlLibTransport` adds this client's identity to every call it makes, signed transfers
|
|
97
|
+
included, and those transfers succeed. What a given storage backend tolerates beyond the
|
|
98
|
+
signature is that backend's business, and nothing in this lane may start depending on it.
|
|
99
|
+
"""
|
|
92
100
|
|
|
93
101
|
declared = session.get("required_headers")
|
|
94
102
|
if declared is None:
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/runs.py
RENAMED
|
@@ -46,6 +46,31 @@ from mostlyright.data_harness.thin.transport import (
|
|
|
46
46
|
#: lane's half of that pin, and ``tests/test_thin_client.py`` holds the two equal.
|
|
47
47
|
PINNED_CONTRACT_VERSION = "3.0.0"
|
|
48
48
|
|
|
49
|
+
#: The header this client names itself under on every Studio call, and the name it gives.
|
|
50
|
+
#:
|
|
51
|
+
#: ⚠ IT IS A COUNTER SELECTOR AND NOTHING ELSE. Studio cannot tell a call from here apart from a
|
|
52
|
+
#: call its own dashboard makes server-side -- both present a Cloud-minted token of the same
|
|
53
|
+
#: credential class, minted by the same function -- so the caller states which one it is and
|
|
54
|
+
#: Studio reads it to decide what to COUNT. It authorizes nothing, no answer changes because it
|
|
55
|
+
#: was sent, and Studio is free to ignore it. Anyone can send it and anyone can withhold it, which
|
|
56
|
+
#: makes the number it feeds a floor with noise in it rather than a measurement of anything.
|
|
57
|
+
#:
|
|
58
|
+
#: Stated per Studio call rather than in the transport, which is the other place every request
|
|
59
|
+
#: passes through and the tempting one, because ``with_user_agent`` is already applied there. The
|
|
60
|
+
#: reason is not that a signed transfer would break under one more header: the transport adds a
|
|
61
|
+
#: user agent to those too, outside the ``required_headers`` the session names, and they succeed.
|
|
62
|
+
#:
|
|
63
|
+
#: The reason is who each header is for. That transport speaks to two kinds of origin -- our own
|
|
64
|
+
#: services, and whatever host a signed transfer URL names, which ``signed_transfer_url`` checks
|
|
65
|
+
#: for a scheme and for the absence of an embedded credential while asserting nothing about whose
|
|
66
|
+
#: storage it is. An identity is owed to every origin a client calls, which is why the user agent
|
|
67
|
+
#: is applied to all of them. A name that means something only to the service keeping the counter
|
|
68
|
+
#: is owed to that service alone, and on the transport it would ride to a third party's storage on
|
|
69
|
+
#: every download, where nothing can count it and nobody asked for it. ``_call`` builds its URL
|
|
70
|
+
#: from ``session.studio_base_url``, so it is the layer that knows the answer is Studio.
|
|
71
|
+
CLIENT_HEADER = "X-Mostlyright-Client"
|
|
72
|
+
CLIENT_NAME = "mr-data"
|
|
73
|
+
|
|
49
74
|
#: The routes. Kept as one table because it is the thing a reviewer checks against the contract.
|
|
50
75
|
START_RUN_PATH = "/v3/runs"
|
|
51
76
|
#: The same collection, read rather than added to. Written out rather than aliased to
|
|
@@ -211,7 +236,11 @@ class StudioApiClient:
|
|
|
211
236
|
shape: type = dict,
|
|
212
237
|
response_headers: dict[str, str] | None = None,
|
|
213
238
|
) -> Any:
|
|
214
|
-
headers = {
|
|
239
|
+
headers = {
|
|
240
|
+
"Accept": "application/json",
|
|
241
|
+
CLIENT_HEADER: CLIENT_NAME,
|
|
242
|
+
**self._session.authorization(),
|
|
243
|
+
}
|
|
215
244
|
if extra_headers:
|
|
216
245
|
headers.update(extra_headers)
|
|
217
246
|
raw_body: bytes | None = None
|
|
@@ -505,6 +534,8 @@ def _studio_refusal(status: int, parsed: Any, path: str) -> ThinLaneError:
|
|
|
505
534
|
|
|
506
535
|
__all__ = [
|
|
507
536
|
"ARTIFACT_DOWNLOAD_SESSION_PATH",
|
|
537
|
+
"CLIENT_HEADER",
|
|
538
|
+
"CLIENT_NAME",
|
|
508
539
|
"GET_RECIPE_PROPOSAL_PATH",
|
|
509
540
|
"GET_RUN_PATH",
|
|
510
541
|
"LIST_RUNS_PATH",
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/stream.py
RENAMED
|
@@ -34,7 +34,11 @@ from mostlyright.data_harness.thin.progress_vocabulary import (
|
|
|
34
34
|
PROGRESS_EVENT_FACTS,
|
|
35
35
|
PROGRESS_SCHEMA_VERSION,
|
|
36
36
|
)
|
|
37
|
-
from mostlyright.data_harness.thin.runs import
|
|
37
|
+
from mostlyright.data_harness.thin.runs import (
|
|
38
|
+
CLIENT_HEADER,
|
|
39
|
+
CLIENT_NAME,
|
|
40
|
+
RUN_EVENTS_STREAM_PATH,
|
|
41
|
+
)
|
|
38
42
|
from mostlyright.data_harness.thin.session import StudioSession
|
|
39
43
|
from mostlyright.data_harness.thin.transport import ThinLaneError, Transport, UrlLibTransport
|
|
40
44
|
|
|
@@ -389,7 +393,11 @@ class RunEventStream:
|
|
|
389
393
|
return True
|
|
390
394
|
return False
|
|
391
395
|
|
|
392
|
-
headers = {
|
|
396
|
+
headers = {
|
|
397
|
+
"Accept": "text/event-stream",
|
|
398
|
+
CLIENT_HEADER: CLIENT_NAME,
|
|
399
|
+
**self._session.authorization(),
|
|
400
|
+
}
|
|
393
401
|
# Resume in Studio's own cursor space when we have one. `from_seq` is only ever the
|
|
394
402
|
# starting position of a watch that has not yet seen a frame.
|
|
395
403
|
if progress.last_event_id:
|
|
@@ -789,8 +789,13 @@ def _ensure_private_directory(path: Path) -> None:
|
|
|
789
789
|
created = True
|
|
790
790
|
except FileExistsError:
|
|
791
791
|
created = False
|
|
792
|
-
if
|
|
793
|
-
|
|
792
|
+
if os.name == "posix":
|
|
793
|
+
if created:
|
|
794
|
+
# The umask may have stripped bits from the mode ``mkdir`` was asked for, and a
|
|
795
|
+
# directory this call just made is one it owns.
|
|
796
|
+
os.chmod(path, 0o700)
|
|
797
|
+
else:
|
|
798
|
+
_narrow_private_directory(path)
|
|
794
799
|
_validate_private_directory(path)
|
|
795
800
|
except OSError:
|
|
796
801
|
raise CredentialStoreError(
|
|
@@ -798,6 +803,42 @@ def _ensure_private_directory(path: Path) -> None:
|
|
|
798
803
|
) from None
|
|
799
804
|
|
|
800
805
|
|
|
806
|
+
def _narrow_private_directory(path: Path) -> None:
|
|
807
|
+
"""Bring a directory this user already owns down to 0700 before the gate below reads it.
|
|
808
|
+
|
|
809
|
+
Another tool can have created the same directory under an ordinary umask, which lands it at
|
|
810
|
+
0755 and makes every later read and write refuse it. It is still this effective user's
|
|
811
|
+
directory, so narrowing it is repair rather than a decision.
|
|
812
|
+
|
|
813
|
+
The descriptor is the whole safety argument. ``O_NOFOLLOW`` and ``O_DIRECTORY`` mean a symlink
|
|
814
|
+
and a non-directory never open at all, so neither can be chmod'ed and both leave through the
|
|
815
|
+
``OSError`` the caller turns into a refusal, and the owner is read off the same descriptor the
|
|
816
|
+
mode is written through, so a directory belonging to somebody else is left exactly as found for
|
|
817
|
+
:func:`_validate_private_directory` to refuse.
|
|
818
|
+
"""
|
|
819
|
+
|
|
820
|
+
try:
|
|
821
|
+
descriptor = os.open(
|
|
822
|
+
path,
|
|
823
|
+
os.O_RDONLY | getattr(os, "O_DIRECTORY", 0) | getattr(os, "O_NOFOLLOW", 0),
|
|
824
|
+
)
|
|
825
|
+
except PermissionError:
|
|
826
|
+
# A directory without its owner-read bit cannot be opened, so the descriptor argument is
|
|
827
|
+
# unavailable and the kind and owner are read from the name instead.
|
|
828
|
+
info = os.lstat(path)
|
|
829
|
+
if stat.S_ISDIR(info.st_mode) and info.st_uid == os.geteuid():
|
|
830
|
+
os.chmod(path, 0o700)
|
|
831
|
+
return
|
|
832
|
+
try:
|
|
833
|
+
info = os.fstat(descriptor)
|
|
834
|
+
if not stat.S_ISDIR(info.st_mode) or info.st_uid != os.geteuid():
|
|
835
|
+
return
|
|
836
|
+
if stat.S_IMODE(info.st_mode) != 0o700:
|
|
837
|
+
os.fchmod(descriptor, 0o700)
|
|
838
|
+
finally:
|
|
839
|
+
os.close(descriptor)
|
|
840
|
+
|
|
841
|
+
|
|
801
842
|
def _validate_private_directory(path: Path) -> None:
|
|
802
843
|
try:
|
|
803
844
|
info = path.stat(follow_symlinks=False)
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/credentials.py
RENAMED
|
@@ -199,7 +199,7 @@ def store_credentials(
|
|
|
199
199
|
except LoginError:
|
|
200
200
|
raise
|
|
201
201
|
except CredentialStoreError as error:
|
|
202
|
-
raise
|
|
202
|
+
raise login_store_error(error) from None
|
|
203
203
|
except OSError:
|
|
204
204
|
raise LoginError(
|
|
205
205
|
"LOGIN_CREDENTIAL_MIGRATION_FAILED",
|
|
@@ -251,7 +251,7 @@ def read_credentials(
|
|
|
251
251
|
except LoginError:
|
|
252
252
|
raise
|
|
253
253
|
except CredentialStoreError as error:
|
|
254
|
-
raise
|
|
254
|
+
raise login_store_error(error) from None
|
|
255
255
|
except OSError:
|
|
256
256
|
raise LoginError(
|
|
257
257
|
"LOGIN_CREDENTIALS_UNREADABLE",
|
|
@@ -392,16 +392,19 @@ def _native_backend_name(directory: Path) -> str:
|
|
|
392
392
|
try:
|
|
393
393
|
return native_backend(directory).name
|
|
394
394
|
except CredentialStoreError as error:
|
|
395
|
-
raise
|
|
395
|
+
raise login_store_error(error) from None
|
|
396
396
|
|
|
397
397
|
|
|
398
398
|
def _backend_for(directory: Path, backend_name: str) -> CredentialBackend:
|
|
399
399
|
if backend_name == "secure-file":
|
|
400
|
-
|
|
400
|
+
try:
|
|
401
|
+
return SecureFileBackend(directory, explicit=True)
|
|
402
|
+
except CredentialStoreError as error:
|
|
403
|
+
raise login_store_error(error) from None
|
|
401
404
|
try:
|
|
402
405
|
backend = native_backend(directory)
|
|
403
406
|
except CredentialStoreError as error:
|
|
404
|
-
raise
|
|
407
|
+
raise login_store_error(error) from None
|
|
405
408
|
if backend.name != backend_name:
|
|
406
409
|
raise LoginError(
|
|
407
410
|
"LOGIN_CREDENTIAL_STORE_UNAVAILABLE",
|
|
@@ -588,7 +591,7 @@ def _install_manifest(path: Path, backend_name: str) -> None:
|
|
|
588
591
|
stage.unlink()
|
|
589
592
|
|
|
590
593
|
|
|
591
|
-
def
|
|
594
|
+
def login_store_error(error: CredentialStoreError) -> LoginError:
|
|
592
595
|
suffix = error.code.removeprefix("CREDENTIAL_")
|
|
593
596
|
details = {
|
|
594
597
|
"CREDENTIAL_STORE_UNAVAILABLE": (
|
|
@@ -606,7 +609,7 @@ def _login_store_error(error: CredentialStoreError) -> LoginError:
|
|
|
606
609
|
}
|
|
607
610
|
return LoginError(
|
|
608
611
|
f"LOGIN_CREDENTIAL_{suffix}",
|
|
609
|
-
details.get(error.code, "the protected credential operation failed"),
|
|
612
|
+
details.get(error.code, error.detail or "the protected credential operation failed"),
|
|
610
613
|
)
|
|
611
614
|
|
|
612
615
|
|
|
@@ -622,6 +625,7 @@ __all__ = [
|
|
|
622
625
|
"credentials_path",
|
|
623
626
|
"default_credentials_dir",
|
|
624
627
|
"install_credential_manifest",
|
|
628
|
+
"login_store_error",
|
|
625
629
|
"read_credentials",
|
|
626
630
|
"refuse_existing_credentials",
|
|
627
631
|
"remove_credential_manifest_under_held_lock",
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/login.py
RENAMED
|
@@ -63,6 +63,7 @@ from mostlyright.data_harness.ux.credentials import (
|
|
|
63
63
|
StoredCredentials,
|
|
64
64
|
credential_transaction_store,
|
|
65
65
|
install_credential_manifest,
|
|
66
|
+
login_store_error,
|
|
66
67
|
refuse_existing_credentials,
|
|
67
68
|
)
|
|
68
69
|
|
|
@@ -529,7 +530,7 @@ def run_login(
|
|
|
529
530
|
if not manifest_path.exists():
|
|
530
531
|
install_credential_manifest(manifest_path, store.backend.name)
|
|
531
532
|
except CredentialStoreError as error:
|
|
532
|
-
raise
|
|
533
|
+
raise login_store_error(error) from None
|
|
533
534
|
live_transport = transport or UrlLibDeviceFlowTransport()
|
|
534
535
|
|
|
535
536
|
authorization = request_device_code(resolved_cloud_url, transport=live_transport)
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/remediation.py
RENAMED
|
@@ -11,7 +11,7 @@ neither affordable nor honest:
|
|
|
11
11
|
* **Families.** Every code prefix is assigned to a family -- 224 of them, plus 18 compound
|
|
12
12
|
prefixes, across 38 families. A family is one paragraph: what this class of failure is about,
|
|
13
13
|
where to look, and what to do. Every prefix has one, so no code can fail to say something useful.
|
|
14
|
-
* **Curated codes.** The
|
|
14
|
+
* **Curated codes.** The 103 failures a person actually meets get their own exact sentences, and
|
|
15
15
|
where one command is the whole answer, the command itself.
|
|
16
16
|
|
|
17
17
|
Those four counts are not a note somebody remembered to update:
|
|
@@ -1770,6 +1770,19 @@ CODES: dict[str, Remediation] = {
|
|
|
1770
1770
|
"mr-data login --force.",
|
|
1771
1771
|
),
|
|
1772
1772
|
),
|
|
1773
|
+
# `mr-data` narrows a credential directory it already owns, so what is left for this code to
|
|
1774
|
+
# report is something it may not touch on its own.
|
|
1775
|
+
"LOGIN_CREDENTIAL_STORE_PERMISSIONS": Remediation(
|
|
1776
|
+
lines=(
|
|
1777
|
+
"The place the device credential is kept is not a private folder this account owns, "
|
|
1778
|
+
"so nothing was read from it or written to it.",
|
|
1779
|
+
"That place is ~/.mostlyright. A folder there that you own is narrowed to your "
|
|
1780
|
+
"account automatically, so the usual causes are a link, a file, or a folder of "
|
|
1781
|
+
"another account at that name, or a volume that does not accept the change.",
|
|
1782
|
+
"Look at what sits at that path and who owns it. Put a folder you own there, then "
|
|
1783
|
+
"run mr-data login again.",
|
|
1784
|
+
),
|
|
1785
|
+
),
|
|
1773
1786
|
"LOGIN_CREDENTIALS_UNREADABLE": Remediation(
|
|
1774
1787
|
lines=(
|
|
1775
1788
|
"The stored credential at the path named above exists but cannot be read as the file "
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/__init__.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/canonical.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/key_seam.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/page_coverage.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/session_probes.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/skill_assets.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/table_manifest.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/acquire.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/activity.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/approvals.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/categories.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/commands.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/narrative.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/parity.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/probe.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/propose.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/recipe.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/research.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/router.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/session.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/transport.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/user_agent.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_catalog.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_datasets.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_handoff.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_query.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_runs.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_secrets.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_stream.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/v4_tables.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/thin/vocabulary.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/__init__.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/attendance.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/clarification.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/cloud_auth.py
RENAMED
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/commands/auth.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/path_kind.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/plain_file.py
RENAMED
|
File without changes
|
{mostlyright_data-0.19.7 → mostlyright_data-0.20.0}/src/mostlyright/data_harness/ux/render.py
RENAMED
|
File without changes
|