Skip to main content
Yanked

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)

Source distribution for sayfirst-contract 0.3.0
File Size Uploaded
sayfirst_contract-0.3.0.tar.gz 183.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sayfirst-contract 0.3.0
File Interpreter ABI Platform
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

Release history Release notifications | RSS feed

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

This release

0.3.0 This release

2 release files

0.2.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page