Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
4514a9e
T078: 16.1, the OpenAI-compatible dialect joins DIALECTS (plan 034)
brettheap Sep 28, 2026
7c83c2c
T079: 16.2, a `model` field the provider receives (plan 034)
brettheap Sep 28, 2026
e9ef951
T080: 16.3, the credential stays a reference; a raw key is refused (p…
brettheap Sep 28, 2026
6e1b894
T078: one throwing call per pytest.raises block in the new tests (Son…
brettheap Sep 28, 2026
a63dcb8
Merge T078's SonarCloud test fix into T079's branch
brettheap Sep 28, 2026
053e207
T079: the intake module's docstring stops counting the binding's fields
brettheap Sep 28, 2026
15adc2b
Merge T079's branch (T078's SonarCloud fix, the intake docstring) int…
brettheap Sep 28, 2026
f92fca4
T080: bound the endpoint before the detector; present only what a bea…
brettheap Sep 28, 2026
68b6e41
T080: the stand-in server's record is reset through monkeypatch (Sona…
brettheap Sep 28, 2026
146b5a2
T080: the console flow's kinds are the ones a broker enrols, said and…
brettheap Sep 28, 2026
4abc6d4
T080: a built-in credential travels only over https:// or to this host
brettheap Sep 28, 2026
d240fd5
T080: the endpoint's checks and the private-route rule move into two …
brettheap Sep 28, 2026
5167084
T080: a request carrying a built-in credential follows no redirect
brettheap Sep 28, 2026
1b0fb3f
T080: no frame a refusal keeps holds a raw credential
brettheap Sep 28, 2026
286655f
T080: a built-in credential over plain http:// uses no proxy
brettheap Sep 28, 2026
3f14bb9
T080: a broker's reference may not take a built-in form; keyring fail…
brettheap Sep 28, 2026
464d8e3
Broker path: a minted token travels only by a private route (follows …
brettheap Sep 29, 2026
823dc03
Broker path: a minted token follows no redirect, uses no proxy, and c…
brettheap Sep 29, 2026
7d465b6
Broker path: a minted token must be presentable, and no mint refusal …
brettheap Sep 29, 2026
af457e6
Broker path tests: two escapes and three docstrings
brettheap Sep 29, 2026
a2c838a
Broker path tests: the redirect case says which codes urllib followed
brettheap Sep 29, 2026
788d764
Broker path: a mint answer whose expiry is no finite number is malformed
brettheap Sep 29, 2026
25788f9
Broker runner: a misbehaving broker's refusal keeps nothing it wrote
brettheap Sep 30, 2026
b847ef3
Broker runner: the answer's bound limits what is read
brettheap Sep 30, 2026
e3eec6b
Broker runner: reap the child when anything else escapes
brettheap Sep 30, 2026
a603a03
Broker runner: a refusal kills the broker's process group, and waits …
brettheap Sep 30, 2026
e75900f
Broker runner: one selector loop, one deadline, no reader thread
brettheap Sep 30, 2026
d07b937
Merge main 047bb4fa into T078 (phase 2 has landed)
brettheap Oct 2, 2026
b04a3a9
Merge T078's head d07b9371 into T079 (main 047bb4fa)
brettheap Oct 2, 2026
4948e6d
Merge T079's head b04a3a95 into T080 (main 047bb4fa)
brettheap Oct 2, 2026
e1a6cb0
Merge T080's head 4948e6dd into the broker hardening (main 047bb4fa)
brettheap Oct 2, 2026
da9e639
Broker hardening: a provider answer nested past the recursion limit i…
brettheap Oct 2, 2026
f0d28a7
Broker hardening tests: one throwing call per pytest.raises block (So…
brettheap Oct 2, 2026
a271d30
Broker hardening: name ValueError alone for the parse's decode error …
brettheap Oct 2, 2026
bbcb565
Broker runner: a refusal after the broker exits kills what is left of…
brettheap Oct 2, 2026
f8bc8ac
Broker runner: signal the group before the broker is reaped, and boun…
brettheap Oct 2, 2026
31bddd8
T100, 16.3a: a served repository's bindings are trusted per machine (…
brettheap Oct 3, 2026
e545165
T100: the rail's trust remedy has its Python twin, and its case mount…
brettheap Oct 3, 2026
a539bb6
T100: the rail probe offers intake before the catalog answers, as a h…
brettheap Oct 3, 2026
c73cbea
T100: the rail's trust sentence names no credential
brettheap Oct 3, 2026
63e534c
Merge main 1130e996 into the broker hardening (T080 landed as #63)
brettheap Oct 3, 2026
1ef4c71
Merge #64's head 63e534cb into T100 (main 1130e996: #63 T080 and #74 …
brettheap Oct 3, 2026
b8323d0
Broker path: L4's cases raise afresh there too, with no token kept
brettheap Oct 3, 2026
e313437
Broker runner: a refused answer kills what is left of the broker's gr…
brettheap Oct 3, 2026
04bcb68
Merge branch 'main' into build/034-p3-broker-credential-hardening
brettheap Oct 3, 2026
3264687
Merge #64's final head 04bcb68e into T100 (e313437b, and main 5e7ab00…
brettheap Oct 3, 2026
11489a5
Merge main 8e377823 into T100 (#64 landed; #73 T075), with 04bcb68e a…
brettheap Oct 3, 2026
7a04590
T100: what a trust policy answers is held to the binding; the store l…
brettheap Oct 3, 2026
8270dff
T100: the governed stand-in takes 5970369724's shape, and answers the…
brettheap Oct 3, 2026
e4b145d
T100: the store refuses an unsupported platform and an unresolvable s…
brettheap Oct 3, 2026
78d1e90
Merge main e49b17c3 into T100 (#77 T084 landed)
brettheap Oct 3, 2026
cb691b1
Merge main 390e2c28 into T100 (#80 T103 landed)
brettheap Oct 3, 2026
24a1c25
T100: the printed trust command runs as printed; only openDox's exact…
brettheap Oct 3, 2026
7012cda
Merge main 0116293a into T100 (#81 T102 landed)
brettheap Oct 3, 2026
db77c4e
T100 round 5: printed commands a shell reads back exactly, unservable…
brettheap Oct 3, 2026
55766d8
Merge main c4b55cc4 (#85, the T102 follow-on) into T100
brettheap Oct 3, 2026
e05c475
T100 round 5: the cases that kill the round's last two mutants (plan …
brettheap Oct 3, 2026
a6c2a84
T100 round 6: a binding the catalog cannot list is told its remedy, n…
brettheap Oct 4, 2026
735d0c1
Merge main ca9e1bd5 (#76, T082) into T100
brettheap Oct 4, 2026
42c98f9
T100 round 7: the lock file is 0600 whatever the umask, and the appro…
brettheap Oct 4, 2026
adb19f1
T100 round 8: the store and its lock file are opened without waiting …
brettheap Oct 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,30 @@ jobs:
# xfail as a skip. T084 landed (openDox-code#77, `e49b17c3`), T082
# merged `main` and removed the five markers in that merge, and the
# five now pass. So T082 adds no skip.
#
# MOVED FROM 11 TO 14 BY plan 034 T100 (#1144 16.3a), for its three
# strict-xfail cases in `tests/test_model_binding_trust.py`, each of
# which waits on another draft and names it: the trust store's
# default location (openDox-code#69's `config.state_dir`), the chat
# rail's trust remedy (openDox-code#74's visible no-model line), and
# a served turn that reaches its model step standalone
# (openDox-code#77's scope seam). JUnit reports an xfail as a skip.
# Each turns into a pass when T100 merges `main` after that draft has
# landed, so this moves back by one with each, WITH the reason, and
# is 11 again once all three are in.
# BACK FROM 14 TO 13: #74 landed on `main` (`9a490405`) and reached
# this branch through #64's merge of `main` `1130e996` (`63e534cb`),
# so the rail case runs and passes, with the rail's trust line it
# waited on.
# BACK FROM 13 TO 12: #69 landed on `main` (`5e7ab003`) and reached
# this branch through #64's final head (`04bcb68e`), so the store's
# default-home case runs and passes. One remains: #77's.
# BACK FROM 12 TO 11: #77 landed on `main` (`e49b17c3`) and this
# branch merged it, so the served-turn case runs and passes. All
# three are in, and the pin is `main`'s again. T100 moves neither
# floor: the floors are T082's re-pin above (3977 / 3966, #76), and
# T100 only adds cases, so its selected and passed counts sit above
# them.
EXPECT_SKIPPED: "11"
run: |
python3 - <<'PY' > triple.env
Expand Down
297 changes: 276 additions & 21 deletions src/opendox/cli_model_binding.py

Large diffs are not rendered by default.

95 changes: 90 additions & 5 deletions src/opendox/doxbench_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,20 +264,25 @@ def brokered_catalog(binding) -> ModelCatalog:
])


def brokered_model_port_factory(binding, *, runner=None, opener=None,
clock=None, notice=None):
def brokered_model_port_factory(binding, *, trust=None, runner=None,
opener=None, clock=None, notice=None):
"""The ZERO-ARGUMENT factory for a BROKER-BACKED port, memoized per process.

Same shape and same reason as `model_port_factory` above: the accessor is
called per REQUEST, and a port built per call would mint a fresh token for
every turn and discard a live one. The seams (`runner`, `opener`, `clock`,
`notice`) pass through so a test can exercise a turn without a broker and
without a provider; production declares none of them."""
without a provider; production declares none of them.

`trust` is the verdict that covers this exact binding (#1144 16.3a;
`doxbench_trust`). The port asks it again before every act, so a port
built without one spawns, reads and contacts nothing."""
from opendox import doxbench_provider as provider_mod

seams = {name: value for name, value in (
("runner", runner), ("opener", opener), ("clock", clock),
("notice", notice)) if value is not None}
seams["trust"] = trust
catalog = brokered_catalog(binding)
lock = threading.Lock()
holder: dict[str, object] = {}
Expand All @@ -297,6 +302,77 @@ def resolve():
return resolve


def unavailable_catalog(binding) -> ModelCatalog:
"""The catalog a binding discloses when it may not be used: its one entry,
exactly as `brokered_catalog` declares it, with `available: false`. The
catalog's wire shape is closed, so no reason rides it (#1144 16.3a)."""
import dataclasses

return ModelCatalog.from_entries([
dataclasses.replace(entry, available=False)
for entry in brokered_catalog(binding).entries])


def trust_gated_model_port_factory(binding, *, checkout_root: Path | str,
bindings_path: Path | str | None = None):
"""The factory for the first approved binding, ONCE THE TRUST POLICY HAS
JUDGED IT (#1144 16.3a; plan 034 T100; RULED openxFactory#656 comment
5962785556, item 2).

THE ONE PLACE A BINDING BECOMES USABLE. The binding was read from the
served repository, so it is used only if the registered trust policy
(`doxbench_trust.policy()`: a host's, or openDox's strict per-machine
store where no host registered one) trusts that exact binding at
`checkout_root`. Trusted, it resolves the brokered port, handed the
verdict. Untrusted, it resolves `doxbench_trust.UntrustedBindingPort`:
the catalog lists the binding `available: false`, a turn is refused by
name, and nothing is spawned, read or contacted. The refusal is said on
stderr, naming the binding and the command that trusts it.

The verdict is HELD TO THIS BINDING (`doxbench_trust.verdict_for`): a
policy that raises trusts nothing, and its words are not repeated; one
that answers for another binding, trusted or not, covers nothing, and the
refusal names THIS binding and its command.

A BINDING THE CATALOG REFUSES IS NEVER TRUSTED, whatever the policy or
the store says (Copilot at openDox-code#82, r4174783280): its id or its
label is not one `brokered_catalog` can list, so the verdict refuses it
before any policy is asked (`doxbench_trust.unservable_because`), and
the start declares the refusing port over an empty catalog rather than
fail on what a repository wrote. So `brokered_catalog` below is only
ever built for a binding it accepts.

`bindings_path` is the document the binding was read from, where a
caller named one, so the command the refusal prints reads that document
too."""
from opendox import doxbench_trust as trust_mod
from opendox.doxbench_model import EMPTY_CATALOG, ModelCatalogError

verdict = trust_mod.verdict_for(binding, root=checkout_root)
if verdict.admits(binding):
return brokered_model_port_factory(binding, trust=verdict)
Comment thread
brettheap marked this conversation as resolved.
bindings = (None if bindings_path is None
else str(Path(bindings_path).resolve()))
sys.stderr.write("[model-provider] " + trust_mod.refusal_message(
verdict.binding_id, verdict.root,
verdict.reason or trust_mod.REASON_NEVER_TRUSTED,
bindings=bindings) + "\n")
try:
catalog = unavailable_catalog(binding)
except ModelCatalogError:
# An id or a label the catalog's schema refuses (a newline, a
# terminal escape, an id past its bound) is a binding no turn could
# name. It is refused by name above, and the catalog lists nothing
# rather than the start failing on what a repository wrote.
catalog = EMPTY_CATALOG
port = trust_mod.UntrustedBindingPort(catalog, verdict, bindings=bindings)

def resolve():
return port

return resolve


def declared_model_port_factory(session_root: Path | str, *,
checkout_root: Path | str,
bindings_path: Path | str | None = None,
Expand Down Expand Up @@ -337,7 +413,14 @@ def declared_model_port_factory(session_root: Path | str, *,
not declared. A binding the DECLARATIONS DOCUMENT SAYS NOTHING ABOUT is
unaffected, byte for byte — it was declared by hand in the settings file by
the operator, and the operator is who approval is a record of (see
`doxbench_intake`'s module docstring for why the rule is not inverted)."""
`doxbench_intake`'s module docstring for why the rule is not inverted).

A DECLARED BINDING IS USED ONLY ONCE IT IS TRUSTED (#1144 16.3a; plan 034
T100; RULED openxFactory#656 comment 5962785556, item 2). The binding was
read from the repository this install serves, so the registered trust
policy judges the first approved one (`trust_gated_model_port_factory`).
A checkout declaring none never asks the policy, so it never touches
openDox's state directory."""
from opendox import doxbench_binding as binding_mod
from opendox import doxbench_intake as intake_mod

Expand Down Expand Up @@ -368,4 +451,6 @@ def declared_model_port_factory(session_root: Path | str, *,
if (harness_present or harness_installed)():
return model_port_factory(Path(session_root), spawn=spawn)
return no_model_port_factory
return brokered_model_port_factory(approved[0])
return trust_gated_model_port_factory(approved[0],
checkout_root=checkout_root,
bindings_path=bindings_path)
77 changes: 59 additions & 18 deletions src/opendox/doxbench_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
from opendox import doxbench_binding as binding_mod
from opendox import doxbench_bridge as bridge_mod
from opendox import doxbench_model as model_mod
from opendox import doxbench_trust as trust_mod

#: THIS MODULE'S OWN NAME, declared so the structural boundary test and the
#: module cannot drift into naming two different files. The test asserts the
Expand Down Expand Up @@ -864,7 +865,7 @@ def _declared_string(document: Mapping, field: str) -> str:
return value


def _broker_operation(binding, operation: str, read, *, runner,
def _broker_operation(binding, operation: str, read, *, runner, trust,
source=None, retry_of: str | None = None):
"""Run one declared `operation` through `runner`, and return what `read`
makes of its answer. It is the one way each of the four operations asks
Expand All @@ -886,7 +887,17 @@ def _broker_operation(binding, operation: str, read, *, runner,
holder's answer on openDox-code#64, 2026-10-02), so a refusal of the
answer kills what is left of the broker's group too (`_settled`). A
runner injected in its place, such as a test's, is given the argv alone
and its answer is read here, as before."""
and its answer is read here, as before.

NO BROKER RUNS FOR A BINDING THE TRUST VERDICT DOES NOT COVER (#1144
16.3a; plan 034 T100; RULED openxFactory#656 comment 5962785556, item
2). All four operations come through here, whichever runner was
injected, so this is where every broker spawn asks: `trust` must be a
`doxbench_trust.TrustVerdict` trusting exactly this binding, or the
binding is refused by name before its invocation is even assembled,
and before either runner's branch below. `doxbench_install` asks the
policy first. This is the defence beneath it."""
trust_mod.require_admitted(binding, trust)
argv = broker_operation_argv(binding, operation, retry_of=retry_of)
if runner is subprocess_broker_runner:
result, failure = _run_broker(argv, source=source,
Expand All @@ -913,7 +924,7 @@ def _broker_operation(binding, operation: str, read, *, runner,
# ---------------------------------------------------------------------------


def hand_off_credential(binding, source, *,
def hand_off_credential(binding, source, *, trust=None,
runner=subprocess_broker_runner) -> str:
"""Hand a human's credential to the broker's `intake` and keep only the
reference.
Expand Down Expand Up @@ -943,9 +954,12 @@ def hand_off_credential(binding, source, *,
here, where both entry points already catch a broker's refusal.

A refusal names `intake` and keeps nothing the broker wrote
(`_broker_operation`)."""
(`_broker_operation`).

`trust` is the verdict covering this exact binding (#1144 16.3a). Without
one the binding is refused by name and `source` is never read."""
return _broker_operation(binding, OPERATION_INTAKE, _intake_reference,
runner=runner, source=source)
runner=runner, source=source, trust=trust)


def _intake_reference(answer: object) -> str:
Expand All @@ -966,7 +980,7 @@ def _intake_reference(answer: object) -> str:
# ---------------------------------------------------------------------------


def mint(binding, *, retry_of: str | None = None,
def mint(binding, *, trust=None, retry_of: str | None = None,
runner=subprocess_broker_runner) -> MintedToken:
"""Ask the broker for a short-lived token.

Expand Down Expand Up @@ -1013,7 +1027,7 @@ def mint(binding, *, retry_of: str | None = None,
return _broker_operation(
binding, OPERATION_MINT,
lambda answer: _minted_token(answer, binding),
runner=runner, retry_of=retry_of)
runner=runner, retry_of=retry_of, trust=trust)


def _minted_token(answer: object, binding) -> MintedToken:
Expand All @@ -1036,7 +1050,7 @@ def _minted_token(answer: object, binding) -> MintedToken:
audit_ref=_declared_string(document, "audit_ref"))


def revoke(binding, *, runner=subprocess_broker_runner) -> str:
def revoke(binding, *, trust=None, runner=subprocess_broker_runner) -> str:
"""Destroy the broker's custody of this binding's credential.

Returns the revocation's own `audit_ref`. The declaration keeps the audit
Expand All @@ -1046,7 +1060,7 @@ def revoke(binding, *, runner=subprocess_broker_runner) -> str:
or the same returned reference, never as the broker's own words. A
refusal names `revoke` (`_broker_operation`)."""
return _broker_operation(binding, OPERATION_REVOKE, _revocation_audit_ref,
runner=runner)
runner=runner, trust=trust)


def _revocation_audit_ref(answer: object) -> str:
Expand All @@ -1058,7 +1072,8 @@ def _revocation_audit_ref(answer: object) -> str:
return _declared_string(document, "audit_ref")


def list_references(binding, *, runner=subprocess_broker_runner) -> list:
def list_references(binding, *, trust=None,
runner=subprocess_broker_runner) -> list:
"""The broker's NON-SECRET reference index, as the declaration returns it.

Safe to read and safe to print: `list` never opens a custody file, and the
Expand All @@ -1067,7 +1082,7 @@ def list_references(binding, *, runner=subprocess_broker_runner) -> list:
an index it does not own invents a second contract for it. A refusal
names `list` (`_broker_operation`)."""
return _broker_operation(binding, OPERATION_LIST, _reference_index,
runner=runner)
runner=runner, trust=trust)


def _reference_index(answer: object) -> list:
Expand Down Expand Up @@ -1137,7 +1152,7 @@ def _os_keyring():
return keyring


def resolve_credential_reference(binding, *, environ=None,
def resolve_credential_reference(binding, *, trust=None, environ=None,
keyring_backend=None) -> str:
"""THE BUILT-IN RESOLVER: the credential an `env:NAME` or
`keyring:SERVICE/USERNAME` reference names, read NOW.
Expand Down Expand Up @@ -1167,7 +1182,15 @@ def resolve_credential_reference(binding, *, environ=None,
that check here. The check is repeated before the first read all the
same, because this is the function that holds the key. What reaches it
is a programming error, like a broker's reference, and nothing has been
read when it is raised."""
read when it is raised.

NOTHING IS READ FOR A BINDING THE TRUST VERDICT DOES NOT COVER (#1144
16.3a; plan 034 T100; RULED openxFactory#656 comment 5962785556, item 2).
`trust` must be a `doxbench_trust.TrustVerdict` trusting exactly this
binding. It is asked after the two programming-error checks above and
BEFORE THE FIRST READ, so a binding a repository declared and nobody
trusted reads no variable and no keyring entry. `doxbench_install` asks
the policy before any port is built. This is the defence beneath it."""
reference = binding_mod.built_in_reference_parts(binding.credential_ref)
if reference is None:
raise AssertionError(
Expand All @@ -1179,6 +1202,7 @@ def resolve_credential_reference(binding, *, environ=None,
f"binding {binding.id!r} routes a credential the built-in "
"resolver reads over a route that is not private, which the "
"record refuses when it is declared; nothing was read")
trust_mod.require_admitted(binding, trust)
if reference.form == binding_mod.CREDENTIAL_REF_ENV:
value = (os.environ if environ is None else environ).get(
reference.name)
Expand Down Expand Up @@ -1539,6 +1563,7 @@ class BrokeredProviderPort:
every capabilities probe."""

def __init__(self, binding, catalog, *,
trust=None,
timeout_seconds: float = 60.0,
runner=subprocess_broker_runner,
opener=urllib.request.urlopen,
Expand All @@ -1555,6 +1580,10 @@ def __init__(self, binding, catalog, *,
f"catalog must be a ModelCatalog, got {type(catalog).__name__}")
self._binding = binding
self._declared_catalog = catalog
# THE TRUST VERDICT (#1144 16.3a). Held, and asked again by every act
# below, so a port built around a binding nobody trusted spawns,
# reads and contacts nothing (`dispatch`).
self._trust = trust
self._timeout_seconds = model_mod.validated_timeout_seconds(
timeout_seconds)
self._runner = runner
Expand Down Expand Up @@ -1584,8 +1613,12 @@ def catalog(self) -> model_mod.ModelCatalog:
The same honesty the harness bridge keeps: a declaration is available
until something is measured, and a broker that has refused is measured.
Nothing here contacts the broker, or reads a reference, to find out.
A later turn that succeeds makes the entry available again."""
if self._available:
A later turn that succeeds makes the entry available again.

A BINDING THE TRUST VERDICT DOES NOT COVER IS NEVER AVAILABLE (#1144
16.3a), so no turn can select it."""
if self._available and isinstance(self._trust, trust_mod.TrustVerdict) \
and self._trust.admits(self._binding):
return self._declared_catalog
return model_mod.ModelCatalog.from_entries([
dataclasses.replace(entry, available=False)
Expand Down Expand Up @@ -1624,12 +1657,20 @@ def dispatch(self, prompt_envelope: object) -> object:
A RECORD NO BROKER ANSWERS takes `_dispatch_without_a_broker` instead
(#1144 box 16.3): no mint, no ledger event, and no retry.

A BINDING THE TRUST VERDICT DOES NOT COVER IS REFUSED FIRST, by name,
before the prompt is rendered, a broker is spawned, a reference is
read or the endpoint is contacted (#1144 16.3a; RULED openxFactory#656
comment 5962785556, item 2). That holds for the auth kind `none` too:
it presents no credential, but it would still send the turn to an
endpoint the binding chose.

EITHER WAY, THE PROVIDER IS CALLED THROUGH `_call_provider`, so a
broker's minted token keeps every rule a built-in credential keeps: no
redirect, no proxy over plain `http://`, and a refusal that chains
nothing (Brett Heap's word of 2026-09-29). The re-mint and the retry
above therefore happen outside every handler, so a refusal raised by
either keeps no context either."""
trust_mod.require_admitted(self._binding, self._trust)
handle = getattr(prompt_envelope, "model_id", None)
if not isinstance(handle, str) or not handle:
entries = self._declared_catalog.entries
Expand Down Expand Up @@ -1687,7 +1728,7 @@ def _dispatch_without_a_broker(self, *, model: str, prompt: str) -> str:
== binding_mod.CREDENTIAL_FROM_BUILT_IN_RESOLVER):
try:
credential = _PresentedCredential(resolve_credential_reference(
self._binding, environ=self._environ,
self._binding, trust=self._trust, environ=self._environ,
keyring_backend=self._keyring_backend))
except BrokerRefused:
with self._lock:
Expand Down Expand Up @@ -1768,8 +1809,8 @@ def _current_token(self, reason: str, *,
return held
self._token = None
try:
minted = mint(self._binding, retry_of=retry_of,
runner=self._runner)
minted = mint(self._binding, trust=self._trust,
retry_of=retry_of, runner=self._runner)
except BrokerRefused:
self._available = False
raise
Expand Down
Loading
Loading