This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
Consider using release 0.3.3 instead.
Reason given by maintainers: security: fixed in 0.3.2; use 0.3.2 or later
sayfirst contract
This distribution publishes generation 1 of the transport-neutral domain
contract and its generated HTTP-over-Unix-socket binding. It has no runtime
dependencies. The scriptable fake is available only through the stub extra.
Scenarios
| Scenario | Binds | Article | Expected |
|---|---|---|---|
allow |
both | 1 | grant=present, outcome=allow, reason=policy_allows |
deny |
both | 1 | outcome=deny, reason=policy_denies |
grant_expired_by_lifetime |
client | 10 | grant=present, grant_use=expired, outcome=allow, reason=policy_allows |
grant_hit_within_lifetime |
client | 10 | grant=present, grant_use=hit, outcome=allow, reason=policy_allows |
grant_miss_after_policy_version_change |
both | 10 | after_policy_change={'grant': 'absent', 'outcome': 'deny', 'reason': 'policy_denies'}, grant=present, outcome=allow, reason=policy_allows |
grant_void_on_arguments_change |
client | 3 | grant=present, grant_use=arguments_changed, outcome=allow, reason=policy_allows |
grant_void_on_connection_loss |
client | 10 | grant=present, grant_use=connection_lost, outcome=allow, reason=policy_allows |
missing_policy |
both | 1 | outcome=deny, reason=policy_absent |
no_grant_on_deny |
both | 10 | grant=absent, outcome=deny, reason=policy_denies |
no_grant_without_signal_channel |
both | 10 | grant=absent, outcome=allow, reason=policy_allows |
policy_unavailable_is_could_not_ask |
both | 1 | grant=absent, problem=policy_unavailable, result=could_not_ask |
review_approve |
both | 12 | outcome=suspend, reason=policy_requires_review, state=approved, after_resolution.outcome=allow, after_resolution.reason=approval_granted |
review_expire |
both | 12 | outcome=suspend, reason=policy_requires_review, state=expired |
review_reject |
both | 12 | outcome=suspend, reason=policy_requires_review, state=rejected, after_resolution.outcome=deny, after_resolution.reason=approval_rejected |
strictest_rule_wins |
server | 1 | grant=absent, outcome=deny, reason=policy_denies |
unknown_outcome |
client | 13 | problem=outcome_unknown, reported_outcome=unknown, result=could_not_ask |
unreachable |
client | 1 | problem=unreachable, result=could_not_ask |
Server conformance replay
Run each server-bound scenario — every row of the table above whose binds is
both or server — against a daemon instance already arranged for that
scenario:
sayfirst-conformance replay \
--socket allow=/run/conformance/allow.sock \
--socket deny=/run/conformance/deny.sock \
--socket grant_miss_after_policy_version_change=/run/conformance/grant_miss_after_policy_version_change.sock \
--socket missing_policy=/run/conformance/missing_policy.sock \
--socket no_grant_on_deny=/run/conformance/no_grant_on_deny.sock \
--socket no_grant_without_signal_channel=/run/conformance/no_grant_without_signal_channel.sock \
--socket policy_unavailable_is_could_not_ask=/run/conformance/policy_unavailable_is_could_not_ask.sock \
--socket review_approve=/run/conformance/review_approve.sock \
--socket review_expire=/run/conformance/review_expire.sock \
--socket review_reject=/run/conformance/review_reject.sock \
--socket strictest_rule_wins=/run/conformance/strictest_rule_wins.sock
Name every server-bound scenario once: with --socket SCENARIO=PATH, or, for
one the deployment cannot arrange a daemon for, with
--expected-absent SCENARIO=REASON. A scenario named by neither has no daemon
to replay against, and it fails. Client-only scenarios are reported as not
applicable because their binds value does not include server. Every result
line contains the scenario name, proven, failed, or not-applicable, and a
reason, and the last line is the whole run's verdict: proven when every
server-bound scenario is proven, failed when any one failed, and unknown
when none failed and not every one was replayed — an expected absence, or a
platform the client cannot verify a peer on — even when another scenario was
proven. The exit status is that verdict's: 0 proven, 1 failed, 3 unknown.
An invalid invocation replays nothing and exits 2.
The command has no way to change a daemon's policy or to move its clock, so
three arrangements are the deployment's to make. The daemon for
grant_miss_after_policy_version_change is asked the same question twice, and
must answer the second under a policy that denies it. The daemon for
policy_unavailable_is_could_not_ask must be unable to read its policy when it
is asked; since a daemon refuses to start on a policy it cannot read, the file
is broken after the start. And the daemons for the three that end a wait must
serve both approval operations — the one for review_expire suspending with a
wait shorter than the replay's --deadline-wait-seconds, and reading as
expired as soon as that wait has passed.
sayfirstd conformance replay is the same replay under the operator surface:
the same options, the same whole-run line and the same exit statuses. Its
scenario lines carry the name, the verdict and the reason; those of
sayfirst-conformance add whether the scenario binds the server and how many
expected members its verdict rests on.
The default expects each per-user daemon to run as the invoking user. System
daemon tests name its numeric account with --expected-uid. The client checks
that identity before sending each request. review_expire waits 61 seconds by
default; a test harness can inject its clock through SocketHarness instead.
The repository acceptance suite uses the same mapping convention under
SAYFIRST_CONFORMANCE_SOCKET_DIR: it looks for <scenario>.sock there and
uses SAYFIRST_CONFORMANCE_EXPECTED_UID when the daemon does not run as the
test user. When the socket directory is not configured, each case is an
expected absence whose reason states that observed configuration fact. When it
is configured, the same inventory runs live and carries no absence claim.
Distribution boundary
The reusable replayer and its HTTP-over-Unix-socket client remain in this
contract distribution. The client verifies the server's peer credential through
the same adapters as the transport client, transport.peer, and maps failures
to impostor, peer_credential_unavailable, unreachable, and
answer_unreadable. A platform no adapter covers is not applicable to a
replay, and on the path a boundary asks through, hold_decision, it is the
could-not-ask peer_identity_unsupported. The socket client is published from
binding.http_unix_socket.client; the replay harness is in the sibling
replay module.
This repository publishes the sayfirst-conformance distribution, the
sayfirst_conformance import package and the sayfirst-conformance script;
it also publishes the operator surface that inspects the daemon, from
packages/cli, as the distribution sayfirstd, the import package sayfirstd
and the console script sayfirstd. Each of those names is claimed once, by one
distribution, and tests/test_client_distribution_names.py holds that against
the [project] tables. The surface re-exports this operation as sayfirstd conformance replay while depending on this contract and on no server
distribution.
The distribution sayfirst-cli, the import package sayfirst_cli and the
console script sayfirst belong to the product command-line interface and are
not published from this repository; the operator settled that on 2026-09-05.
This distribution installs no console script of its own, so nothing here is
bound to the name of a surface that forwards to it. The operator surface
sayfirstd is the one that reaches this operation today; the product
command-line interface may reach it through these same modules, and no release
of it does so yet.
Metadata
Release files for sayfirst-contract 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sayfirst_contract-0.3.0.tar.gz | 183.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sayfirst_contract-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 327.5 kB
Release files / sayfirst_contract-0.3.0.tar.gz
| Download URL | sayfirst_contract-0.3.0.tar.gz |
|---|---|
| Size | 183.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bddd3b069d2d75134a323faecf0adbbd00c3142bc365850166ab17a59f0d82fc
|
|
BLAKE2b-256 checksum How to use checksums |
0c66bb177dff51ddffd79574d08f5532baeb8aeb6106ac31520512c3564608c9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.5
|
Release files / sayfirst_contract-0.3.0-py3-none-any.whl
| Download URL | sayfirst_contract-0.3.0-py3-none-any.whl |
|---|---|
| Size | 144.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b0207ac67abb6e8fa8c80fa38c21fe3fb8cf8af2e9cfeccbf355751a5bdb1e09
|
|
BLAKE2b-256 checksum How to use checksums |
2a931280febae7d28ee2aed9f527f35b2a1e835cf99882c727aee1191706cee5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency log