fkyh 0.1.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.
Files changed (171) hide show
  1. fkyh-0.1.0/.github/workflows/ci.yml +376 -0
  2. fkyh-0.1.0/ATTESTATION.md +944 -0
  3. fkyh-0.1.0/CONTRIBUTING.md +635 -0
  4. fkyh-0.1.0/LICENSE +202 -0
  5. fkyh-0.1.0/MANIFEST.in +58 -0
  6. fkyh-0.1.0/PKG-INFO +485 -0
  7. fkyh-0.1.0/PLAN.md +247 -0
  8. fkyh-0.1.0/PROVE-IT.md +469 -0
  9. fkyh-0.1.0/README.md +457 -0
  10. fkyh-0.1.0/ROADMAP.md +245 -0
  11. fkyh-0.1.0/SECURITY.md +390 -0
  12. fkyh-0.1.0/SPEC.md +1327 -0
  13. fkyh-0.1.0/STATUS.md +268 -0
  14. fkyh-0.1.0/audit/workerA.md +268 -0
  15. fkyh-0.1.0/audit/workerB.md +459 -0
  16. fkyh-0.1.0/audit/workerC.md +622 -0
  17. fkyh-0.1.0/audit/workerD.md +712 -0
  18. fkyh-0.1.0/audit/workerE.md +824 -0
  19. fkyh-0.1.0/audit/workerF.md +946 -0
  20. fkyh-0.1.0/audit/workerG.md +1042 -0
  21. fkyh-0.1.0/audit/workerH.md +818 -0
  22. fkyh-0.1.0/contracts/fkyh-registry/.cargo/config.toml +6 -0
  23. fkyh-0.1.0/contracts/fkyh-registry/Cargo.lock +2120 -0
  24. fkyh-0.1.0/contracts/fkyh-registry/Cargo.toml +15 -0
  25. fkyh-0.1.0/contracts/fkyh-registry/src/lib.rs +558 -0
  26. fkyh-0.1.0/contracts/fkyh-registry/src/test.rs +569 -0
  27. fkyh-0.1.0/examples/attestation-consumer-go/README.md +132 -0
  28. fkyh-0.1.0/examples/attestation-consumer-go/attestation/consumer.go +648 -0
  29. fkyh-0.1.0/examples/attestation-consumer-go/attestation/consumer_test.go +337 -0
  30. fkyh-0.1.0/examples/attestation-consumer-go/attestation/jcs.go +215 -0
  31. fkyh-0.1.0/examples/attestation-consumer-go/go.mod +3 -0
  32. fkyh-0.1.0/examples/attestation-consumer-go/main.go +203 -0
  33. fkyh-0.1.0/examples/fk-yh-node/README.md +125 -0
  34. fkyh-0.1.0/examples/fk-yh-node/node.py +260 -0
  35. fkyh-0.1.0/examples/fk-yh-node/run_demo.sh +51 -0
  36. fkyh-0.1.0/examples/fk-yh-node/run_independent_loop.sh +101 -0
  37. fkyh-0.1.0/examples/fk-yh-node/verifier.py +155 -0
  38. fkyh-0.1.0/examples/go-reference/README.md +102 -0
  39. fkyh-0.1.0/examples/go-reference/build_oracle.sh +34 -0
  40. fkyh-0.1.0/examples/go-reference/go.mod +3 -0
  41. fkyh-0.1.0/examples/go-reference/main.go +227 -0
  42. fkyh-0.1.0/examples/go-reference/oracle.go +213 -0
  43. fkyh-0.1.0/examples/grafana/README.md +168 -0
  44. fkyh-0.1.0/examples/grafana/dashboard.json +842 -0
  45. fkyh-0.1.0/examples/grafana/docker-compose.yml +98 -0
  46. fkyh-0.1.0/examples/grafana/prometheus.yml +37 -0
  47. fkyh-0.1.0/examples/grafana/provisioning/dashboards/fkyh.yaml +26 -0
  48. fkyh-0.1.0/examples/grafana/provisioning/datasources/fkyh-prometheus.yaml +27 -0
  49. fkyh-0.1.0/examples/hello-world.py +123 -0
  50. fkyh-0.1.0/examples/independent-consumer/README.md +109 -0
  51. fkyh-0.1.0/examples/independent-consumer/run_conformance.py +79 -0
  52. fkyh-0.1.0/examples/independent-consumer/thirdparty_consumer.py +371 -0
  53. fkyh-0.1.0/fixtures/ORACLES.json +191 -0
  54. fkyh-0.1.0/fixtures/attestations/MANIFEST-COVERAGE.md +48 -0
  55. fkyh-0.1.0/fixtures/attestations/README.md +178 -0
  56. fkyh-0.1.0/fixtures/attestations/TEST-ONLY-README.md +11 -0
  57. fkyh-0.1.0/fixtures/attestations/TEST-ONLY-private-key.hex +1 -0
  58. fkyh-0.1.0/fixtures/attestations/TEST-ONLY-revoked-private-key.hex +1 -0
  59. fkyh-0.1.0/fixtures/attestations/evidence/payments.conf +2 -0
  60. fkyh-0.1.0/fixtures/attestations/evidence-digest-mismatch.json +22 -0
  61. fkyh-0.1.0/fixtures/attestations/evidence-missing.json +22 -0
  62. fkyh-0.1.0/fixtures/attestations/evidence-no-digest.json +21 -0
  63. fkyh-0.1.0/fixtures/attestations/evidence-null-digest.json +22 -0
  64. fkyh-0.1.0/fixtures/attestations/evidence-unreadable.json +22 -0
  65. fkyh-0.1.0/fixtures/attestations/expired.json +22 -0
  66. fkyh-0.1.0/fixtures/attestations/manifest.json +162 -0
  67. fkyh-0.1.0/fixtures/attestations/missing-signature.json +21 -0
  68. fkyh-0.1.0/fixtures/attestations/not-yet-valid.json +22 -0
  69. fkyh-0.1.0/fixtures/attestations/revoked-verifier.json +22 -0
  70. fkyh-0.1.0/fixtures/attestations/section-4-3-worked-example.json +22 -0
  71. fkyh-0.1.0/fixtures/attestations/tampered.json +22 -0
  72. fkyh-0.1.0/fixtures/attestations/trust.json +21 -0
  73. fkyh-0.1.0/fixtures/attestations/unauthorized-policy.json +22 -0
  74. fkyh-0.1.0/fixtures/attestations/unauthorized-verifier.json +22 -0
  75. fkyh-0.1.0/fixtures/attestations/unsupported-version.json +22 -0
  76. fkyh-0.1.0/fixtures/attestations/valid-failed.json +22 -0
  77. fkyh-0.1.0/fixtures/attestations/valid-inconclusive.json +16 -0
  78. fkyh-0.1.0/fixtures/attestations/valid-verified.json +22 -0
  79. fkyh-0.1.0/fixtures/attestations/wrong-attempt.json +22 -0
  80. fkyh-0.1.0/fixtures/attestations/wrong-task.json +22 -0
  81. fkyh-0.1.0/fixtures/executor/conformance.json +121 -0
  82. fkyh-0.1.0/fixtures/jcs/input/arrays.json +8 -0
  83. fkyh-0.1.0/fixtures/jcs/input/french.json +6 -0
  84. fkyh-0.1.0/fixtures/jcs/input/structures.json +8 -0
  85. fkyh-0.1.0/fixtures/jcs/input/unicode.json +3 -0
  86. fkyh-0.1.0/fixtures/jcs/input/values.json +5 -0
  87. fkyh-0.1.0/fixtures/jcs/input/weird.json +11 -0
  88. fkyh-0.1.0/fixtures/jcs/output/arrays.json +1 -0
  89. fkyh-0.1.0/fixtures/jcs/output/french.json +1 -0
  90. fkyh-0.1.0/fixtures/jcs/output/structures.json +1 -0
  91. fkyh-0.1.0/fixtures/jcs/output/unicode.json +1 -0
  92. fkyh-0.1.0/fixtures/jcs/output/values.json +1 -0
  93. fkyh-0.1.0/fixtures/jcs/output/weird.json +1 -0
  94. fkyh-0.1.0/fixtures/rfc/rfc8259.txt +899 -0
  95. fkyh-0.1.0/fixtures/rfc/rfc8785.txt +984 -0
  96. fkyh-0.1.0/fixtures/stellar/caip-2.md +111 -0
  97. fkyh-0.1.0/fixtures/stellar/cap-0046-08.md +109 -0
  98. fkyh-0.1.0/fixtures/stellar/cap-0046-11.md +605 -0
  99. fkyh-0.1.0/fixtures/stellar/cap-0046-12.md +600 -0
  100. fkyh-0.1.0/fixtures/stellar/cap-0071.md +149 -0
  101. fkyh-0.1.0/fixtures/stellar/sep-0041.md +352 -0
  102. fkyh-0.1.0/fixtures/stellar/soroban-sdk-crypto.rs +509 -0
  103. fkyh-0.1.0/fixtures/x402/core-v2.md +729 -0
  104. fkyh-0.1.0/fixtures/x402/scheme-exact-stellar.md +231 -0
  105. fkyh-0.1.0/fixtures/x402/scheme-exact.md +100 -0
  106. fkyh-0.1.0/fixtures/x402/transport-http-v1.md +160 -0
  107. fkyh-0.1.0/fixtures/x402/transport-http-v2.md +192 -0
  108. fkyh-0.1.0/fkyh/__init__.py +37 -0
  109. fkyh-0.1.0/fkyh/__main__.py +199 -0
  110. fkyh-0.1.0/fkyh/attestation.py +623 -0
  111. fkyh-0.1.0/fkyh/discovery.py +802 -0
  112. fkyh-0.1.0/fkyh/gossip.py +377 -0
  113. fkyh-0.1.0/fkyh/jcs.py +236 -0
  114. fkyh-0.1.0/fkyh/keys.py +233 -0
  115. fkyh-0.1.0/fkyh/metrics.py +216 -0
  116. fkyh-0.1.0/fkyh/node.py +349 -0
  117. fkyh-0.1.0/fkyh/servicetype.py +399 -0
  118. fkyh-0.1.0/fkyh/signer.py +163 -0
  119. fkyh-0.1.0/fkyh/signing.py +598 -0
  120. fkyh-0.1.0/fkyh/state.py +269 -0
  121. fkyh-0.1.0/fkyh.egg-info/PKG-INFO +485 -0
  122. fkyh-0.1.0/fkyh.egg-info/SOURCES.txt +169 -0
  123. fkyh-0.1.0/fkyh.egg-info/dependency_links.txt +1 -0
  124. fkyh-0.1.0/fkyh.egg-info/entry_points.txt +2 -0
  125. fkyh-0.1.0/fkyh.egg-info/requires.txt +9 -0
  126. fkyh-0.1.0/fkyh.egg-info/top_level.txt +1 -0
  127. fkyh-0.1.0/pyproject.toml +58 -0
  128. fkyh-0.1.0/pytest.ini +8 -0
  129. fkyh-0.1.0/scripts/publish-gate.sh +925 -0
  130. fkyh-0.1.0/setup.cfg +4 -0
  131. fkyh-0.1.0/tests/conftest.py +32 -0
  132. fkyh-0.1.0/tests/oracle_headers.py +294 -0
  133. fkyh-0.1.0/tests/test_attestation.py +423 -0
  134. fkyh-0.1.0/tests/test_audit_attestation_canonicalisation.py +743 -0
  135. fkyh-0.1.0/tests/test_audit_attestation_in_toto.py +1202 -0
  136. fkyh-0.1.0/tests/test_audit_attestation_trust_replay.py +829 -0
  137. fkyh-0.1.0/tests/test_audit_comparison_participation.py +734 -0
  138. fkyh-0.1.0/tests/test_audit_discovery_gossip.py +708 -0
  139. fkyh-0.1.0/tests/test_audit_key_id_derivation.py +228 -0
  140. fkyh-0.1.0/tests/test_audit_metrics_dashboard.py +425 -0
  141. fkyh-0.1.0/tests/test_audit_payments_security.py +612 -0
  142. fkyh-0.1.0/tests/test_audit_section_references.py +381 -0
  143. fkyh-0.1.0/tests/test_audit_signed_headers.py +707 -0
  144. fkyh-0.1.0/tests/test_ci_contract.py +653 -0
  145. fkyh-0.1.0/tests/test_discovery.py +192 -0
  146. fkyh-0.1.0/tests/test_discovery_live.py +159 -0
  147. fkyh-0.1.0/tests/test_discovery_live_servicetype.py +368 -0
  148. fkyh-0.1.0/tests/test_doc_claims.py +1334 -0
  149. fkyh-0.1.0/tests/test_go_consumer.py +134 -0
  150. fkyh-0.1.0/tests/test_go_oracle.py +156 -0
  151. fkyh-0.1.0/tests/test_gossip.py +187 -0
  152. fkyh-0.1.0/tests/test_gossip_signing.py +262 -0
  153. fkyh-0.1.0/tests/test_grafana_dashboard.py +237 -0
  154. fkyh-0.1.0/tests/test_independent_consumer.py +201 -0
  155. fkyh-0.1.0/tests/test_independent_verification.py +307 -0
  156. fkyh-0.1.0/tests/test_keys.py +177 -0
  157. fkyh-0.1.0/tests/test_metrics.py +130 -0
  158. fkyh-0.1.0/tests/test_node.py +174 -0
  159. fkyh-0.1.0/tests/test_oracle_headers.py +237 -0
  160. fkyh-0.1.0/tests/test_oracle_pins.py +804 -0
  161. fkyh-0.1.0/tests/test_prove_it.py +474 -0
  162. fkyh-0.1.0/tests/test_publication_truth.py +484 -0
  163. fkyh-0.1.0/tests/test_publish_gate.py +593 -0
  164. fkyh-0.1.0/tests/test_service_type_freeze.py +155 -0
  165. fkyh-0.1.0/tests/test_servicetype.py +401 -0
  166. fkyh-0.1.0/tests/test_signing.py +727 -0
  167. fkyh-0.1.0/tests/test_spec_conformance.py +567 -0
  168. fkyh-0.1.0/tests/test_spec_examples.py +294 -0
  169. fkyh-0.1.0/tests/test_spec_signed_gossip.py +238 -0
  170. fkyh-0.1.0/tests/test_state.py +194 -0
  171. fkyh-0.1.0/tests/test_verify_cli.py +223 -0
@@ -0,0 +1,376 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ python:
11
+ name: Python package and tests
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ # The floor `pyproject.toml` declares must be TESTED, not merely
15
+ # stated. A `requires-python` nobody ever runs is a promise with
16
+ # no evidence behind it, and this repository's rule is that a
17
+ # document describing a thing is not the same as a check on the
18
+ # thing. A matrix is the cheapest way to make the promise real.
19
+ #
20
+ # This is also the only job that runs the whole suite
21
+ # (`python -m pytest tests/`), which is why the declared floor is
22
+ # tested HERE and nowhere else. Every other job checks a slice of
23
+ # the repository, and each one says what it checks, and why it
24
+ # pins a single interpreter, beside its own `setup-python` step.
25
+ fail-fast: false
26
+ matrix:
27
+ python-version: ["3.11", "3.12"]
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ with:
31
+ # The publish gate audits the DEFAULT BRANCH's tree, and the
32
+ # test suite runs it. A shallow checkout has no origin/main, so
33
+ # the gate skips everything and the suite fails for a reason that
34
+ # has nothing to do with the code. Full history, always.
35
+ fetch-depth: 0
36
+
37
+ - uses: actions/setup-python@v5
38
+ with:
39
+ python-version: ${{ matrix.python-version }}
40
+
41
+ # Two tests in the suite build Go binaries (the attestation consumer
42
+ # and the executor oracle). They skip when Go is missing, which
43
+ # silently turned them into no-ops. Install Go here so they really
44
+ # run in the main job, not just in the Go-specific jobs.
45
+ - uses: actions/setup-go@v5
46
+ with:
47
+ go-version: "1.22"
48
+
49
+ # Installing Go is not the same as the Go code building. Both
50
+ # builders inside the suite call `pytest.skip` when `go build`
51
+ # fails (tests/test_go_consumer.py:38, tests/test_go_oracle.py:46),
52
+ # so a Go source change that does not compile turns four
53
+ # cross-language pins into four SKIPS and leaves this job GREEN --
54
+ # a gate that inspects less than it governs, which is the exact
55
+ # failure this repository has already been bitten by. Measured: with
56
+ # a deliberate syntax error in examples/go-reference/oracle.go the
57
+ # suite reported "4 skipped" and exited 0. Build both binaries HERE,
58
+ # where a compile error is a failed step, so the suite's own skip can
59
+ # never be the only thing that notices.
60
+ - name: The Go cross-language pins must not degrade into skips
61
+ run: |
62
+ set -euo pipefail
63
+ cd examples/attestation-consumer-go
64
+ go build -o /tmp/attestation-consumer .
65
+ go build ./...
66
+ cd ../go-reference
67
+ go build -tags oracle -o /tmp/fk-yh-oracle .
68
+
69
+ - name: Install dependencies
70
+ # `.[test]` is the single source of truth for what the suite
71
+ # needs: the optional `prometheus_client` and `pyyaml` packages
72
+ # are not decoration, they are what lets the metrics and the
73
+ # Grafana dashboard tests actually assert. Without them those
74
+ # tests skip, and a test that skips is a gate that inspects
75
+ # less than it governs.
76
+ run: |
77
+ python -m pip install --upgrade pip
78
+ python -m pip install -e '.[test]'
79
+
80
+ - name: Run the test suite
81
+ run: python -m pytest tests/ -q
82
+
83
+ - name: The hello-world example must actually run
84
+ run: python examples/hello-world.py
85
+
86
+ mDNS:
87
+ name: Live mDNS round trip
88
+ # The live discovery tests need the platform's dns-sd tool, which is
89
+ # macOS only. This job exists because the unit tests could not catch
90
+ # the TXT format bug -- they passed while the implementation could not
91
+ # talk to the network at all.
92
+ # The label matters, and so does the measurement. macos-14 is
93
+ # DEPRECATED (actions/runner-images), and bare macos-15 also never
94
+ # acquired a runner: the job queued and was cancelled with
95
+ # runner_name="" and steps=0, four attempts running, while the six
96
+ # ubuntu-latest jobs in the SAME run took runners within two seconds.
97
+ # At the same moment, macos-latest jobs in other repos were landing
98
+ # on real runners (setup-python 5/5, pypa/pip 4/4, Homebrew
99
+ # macos-26 2/2) -- so this was never a macOS capacity shortage, it
100
+ # is this label not being served. macos-latest resolves to the
101
+ # current GA macOS, which is the version the live suite is verified
102
+ # against (macOS 26.4.1: 10/10 passing locally).
103
+ runs-on: macos-latest
104
+ steps:
105
+ - uses: actions/checkout@v4
106
+ with:
107
+ # The publish gate audits the DEFAULT BRANCH's tree, and the
108
+ # test suite runs it. A shallow checkout has no origin/main, so
109
+ # the gate skips everything and the suite fails for a reason that
110
+ # has nothing to do with the code. Full history, always.
111
+ fetch-depth: 0
112
+
113
+ # One Python version (3.12), deliberately, not a matrix. What this
114
+ # job checks is a live-network round trip that needs the platform's
115
+ # dns-sd tool, and dns-sd is macOS only by nature -- so the
116
+ # interpreter version is incidental to the thing being checked.
117
+ # The declared floor is still exercised where it can be: the
118
+ # `python` job's matrix runs the whole suite on the floor,
119
+ # including the discovery unit tests. The live discovery files
120
+ # skip there, because dns-sd is missing on that runner -- which is
121
+ # exactly why this job exists.
122
+ - uses: actions/setup-python@v5
123
+ with:
124
+ python-version: "3.12"
125
+
126
+ - name: Install dependencies
127
+ run: |
128
+ python -m pip install --upgrade pip
129
+ python -m pip install pytest cryptography
130
+
131
+ - name: Advertise and resolve over a real network
132
+ # The glob, not a filename: a new live test file that is not
133
+ # listed here silently never runs, which is the same failure as
134
+ # not writing the test at all. The TXT format bug was invisible
135
+ # because the unit tests could not talk to the network.
136
+ run: python3 -m pytest tests/test_discovery_live*.py -v
137
+
138
+ - name: The audit live pins must run on a runner too
139
+ # These pins read the wire back -- the TXT record as a conforming
140
+ # reader sees it, and whether a derived service type really is a
141
+ # separate registration. They had never executed on a runner,
142
+ # because the glob above does not match this file AND the pins
143
+ # are gated behind FKYH_AUDIT_LIVE=1.
144
+ #
145
+ # A pin that never runs is a pin that cannot fail, and these
146
+ # proved it: one of them was found RED the first time it was
147
+ # actually executed (2026-10-22), still asserting the behaviour
148
+ # the fix had already removed. The ports are disjoint from the
149
+ # tests above (19990-19997 against 19873/19880-19884) and the
150
+ # instance names differ, so the two groups do not collide; this
151
+ # step runs after the one above rather than beside it.
152
+ #
153
+ # The gate is set for this step only. Without it the four live
154
+ # pins SKIP, and a skip in CI is indistinguishable from a pass.
155
+ env:
156
+ FKYH_AUDIT_LIVE: "1"
157
+ run: python3 -m pytest tests/test_audit_discovery_gossip.py -v
158
+
159
+ goAttestation:
160
+ name: Go attestation consumer (cross-language)
161
+ # The attestation protocol is implemented twice in Python and once in Go.
162
+ # The Go one is the interesting one: two Python implementations can share
163
+ # a misunderstanding and never find it, because they share a language, a
164
+ # JSON library and a set of habits. This job proves the protocol
165
+ # interoperates ACROSS languages, not merely across implementations.
166
+ runs-on: ubuntu-latest
167
+ steps:
168
+ - uses: actions/checkout@v4
169
+ with:
170
+ # The publish gate audits the DEFAULT BRANCH's tree, and the
171
+ # test suite runs it. A shallow checkout has no origin/main, so
172
+ # the gate skips everything and the suite fails for a reason that
173
+ # has nothing to do with the code. Full history, always.
174
+ fetch-depth: 0
175
+
176
+ - uses: actions/setup-go@v5
177
+ with:
178
+ go-version: "1.22"
179
+
180
+ - name: The Go consumer must satisfy the published manifest
181
+ run: |
182
+ cd examples/attestation-consumer-go
183
+ go build -o /tmp/attestation-consumer .
184
+ /tmp/attestation-consumer --conformance ../../fixtures/attestations
185
+
186
+ - name: The Go test suite must pass
187
+ run: cd examples/attestation-consumer-go && go test ./...
188
+
189
+ conformance:
190
+ name: Go executor oracle (pinned contract)
191
+ # The Go oracle implements the same 5-stage guarded executor as the
192
+ # Python reference. The Python side lives in the LAM repository, which
193
+ # this repository cannot reach, so what is checked here is the oracle
194
+ # against the pinned contract in fixtures/executor/conformance.json.
195
+ #
196
+ # The previous version of this job parsed the oracle's stdout as a
197
+ # single JSON array. The oracle emits one JSON object per line, so
198
+ # `out[0]` raised KeyError and the job failed on every run from the
199
+ # repository's first commit. The check now lives in a test, which runs
200
+ # locally as well as here.
201
+ runs-on: ubuntu-latest
202
+ steps:
203
+ - uses: actions/checkout@v4
204
+ with:
205
+ # The publish gate audits the DEFAULT BRANCH's tree, and the
206
+ # test suite runs it. A shallow checkout has no origin/main, so
207
+ # the gate skips everything and the suite fails for a reason that
208
+ # has nothing to do with the code. Full history, always.
209
+ fetch-depth: 0
210
+
211
+ - uses: actions/setup-go@v5
212
+ with:
213
+ go-version: "1.22"
214
+
215
+ # One Python version (3.12), deliberately, not a matrix. What this
216
+ # job checks is the Go oracle against the pinned contract, and the
217
+ # Go version is pinned separately at 1.22. The Python step here
218
+ # only parses a JSON fixture, so the interpreter version cannot
219
+ # change the oracle's verdict. The declared floor is exercised for
220
+ # the suite by the `python` job's matrix.
221
+ - uses: actions/setup-python@v5
222
+ with:
223
+ python-version: "3.12"
224
+
225
+ - name: Install dependencies
226
+ run: |
227
+ python -m pip install --upgrade pip
228
+ python -m pip install pytest
229
+
230
+ - name: Build the Go oracle
231
+ run: |
232
+ chmod +x examples/go-reference/build_oracle.sh
233
+ ./examples/go-reference/build_oracle.sh /tmp/fk-yh-oracle
234
+
235
+ - name: The oracle must agree with the pinned contract
236
+ run: python -m pytest tests/test_go_oracle.py -v
237
+
238
+ - name: The conformance fixture must be internally consistent
239
+ # The contract is the shared document both implementations are
240
+ # pinned to. If it is malformed, every check against it is
241
+ # meaningless, so validate it on its own.
242
+ run: |
243
+ python3 - <<'PY'
244
+ import json, sys
245
+ with open("fixtures/executor/conformance.json") as fh:
246
+ doc = json.load(fh)
247
+ cases = doc["cases"]
248
+ if not cases:
249
+ print("the conformance fixture has no cases")
250
+ sys.exit(1)
251
+ stages = {c["expect"]["stage"] for c in cases}
252
+ wanted = {"prepare", "authorize", "execute", "commit"}
253
+ missing = wanted - stages
254
+ if missing:
255
+ print("the conformance fixture never exercises:", sorted(missing))
256
+ sys.exit(1)
257
+ print(f"{len(cases)} conformance cases, stages covered: {sorted(stages)}")
258
+ PY
259
+
260
+ attestation:
261
+ name: Attestation conformance fixtures
262
+ runs-on: ubuntu-latest
263
+ steps:
264
+ - uses: actions/checkout@v4
265
+ with:
266
+ # The publish gate audits the DEFAULT BRANCH's tree, and the
267
+ # test suite runs it. A shallow checkout has no origin/main, so
268
+ # the gate skips everything and the suite fails for a reason that
269
+ # has nothing to do with the code. Full history, always.
270
+ fetch-depth: 0
271
+
272
+ # One Python version (3.12), deliberately, not a matrix. What this
273
+ # job checks is the published conformance consumer, run as a
274
+ # SCRIPT, so what is under test is the consumer's own output and
275
+ # not the interpreter underneath it. The floor is covered for the
276
+ # consumer as well: the suite runs that same script as a
277
+ # subprocess on the interpreter that runs the suite
278
+ # (tests/test_independent_consumer.py), so the `python` job's
279
+ # matrix exercises the consumer on the declared floor too.
280
+ - uses: actions/setup-python@v5
281
+ with:
282
+ python-version: "3.12"
283
+
284
+ - name: Install dependencies
285
+ run: |
286
+ python -m pip install --upgrade pip
287
+ python -m pip install pytest cryptography
288
+
289
+ - name: The independent consumer must satisfy the published manifest
290
+ # examples/independent-consumer/ is a second implementation written
291
+ # from ATTESTATION.md alone, importing nothing from the package. It is
292
+ # the artefact that proves the specification is implementable from the
293
+ # document rather than only by someone who has read the reference
294
+ # code. If it and the package ever disagree, the specification is
295
+ # ambiguous and the fixtures are not trustworthy.
296
+ run: |
297
+ python3 examples/independent-consumer/run_conformance.py
298
+
299
+ - name: The published fixtures must satisfy their own manifest
300
+ # An independent consumer, implemented from ATTESTATION.md alone,
301
+ # validates the published fixture set. If the corpus and the spec
302
+ # ever drift apart, this fails.
303
+ run: |
304
+ python3 - <<'PY'
305
+ import json, os, sys
306
+ sys.path.insert(0, ".")
307
+ from fkyh.attestation import Consumer, TrustConfig
308
+
309
+ fx = "fixtures/attestations"
310
+ manifest = json.load(open(os.path.join(fx, "manifest.json")))
311
+ trust = TrustConfig.load(os.path.join(fx, "trust.json"))
312
+ # The published evidence directory, so the consumer re-derives
313
+ # the digests as section 10 instructs. Without it the evidence
314
+ # codes of section 7 step 9 are never reached.
315
+ evidence = os.path.join(fx, "evidence")
316
+ ok = bad = 0
317
+ for name, expected in sorted(manifest["fixtures"].items()):
318
+ att = json.load(open(os.path.join(fx, expected["file"])))
319
+ result = Consumer(trust, evidence_root=evidence).validate(
320
+ att, expected_task_id=manifest["task_id"],
321
+ expected_attempt_id=manifest["attempt_id"])
322
+ good = (result.code == expected["expected_code"]
323
+ and result.result == expected["expected_result"])
324
+ ok += good
325
+ bad += not good
326
+ if not good:
327
+ print(f"FAIL {name}: {result.code}/{result.result} "
328
+ f"expected {expected['expected_code']}/"
329
+ f"{expected['expected_result']}")
330
+ for seq in manifest.get("sequences", []):
331
+ spent = set()
332
+ for step in seq["steps"]:
333
+ att = json.load(open(os.path.join(fx, step["file"])))
334
+ result = Consumer(trust, evidence_root=evidence,
335
+ spent=spent).validate(
336
+ att, expected_task_id=manifest["task_id"],
337
+ expected_attempt_id=manifest["attempt_id"])
338
+ good = (result.code == step["expected_code"]
339
+ and result.result == step["expected_result"])
340
+ ok += good
341
+ bad += not good
342
+ print(f"{ok}/{ok + bad} conformance checks passed")
343
+ sys.exit(0 if bad == 0 else 1)
344
+ PY
345
+
346
+ soroban-registry:
347
+ name: Soroban registry contract
348
+ # The contract is native-testable: cargo test needs no stellar-cli and
349
+ # no wasm target. The wasm BUILD is deliberately not in CI -- the SDK's
350
+ # build script requires stellar-cli v25.2.0+ for spec shaking, and
351
+ # claiming the contract builds in CI without that toolchain would be
352
+ # the same class of claim this repository keeps deleting.
353
+ runs-on: ubuntu-latest
354
+ steps:
355
+ - uses: actions/checkout@v4
356
+ with:
357
+ # The publish gate audits the DEFAULT BRANCH's tree, and the
358
+ # test suite runs it. A shallow checkout has no origin/main, so
359
+ # the gate skips everything and the suite fails for a reason that
360
+ # has nothing to do with the code. Full history, always.
361
+ fetch-depth: 0
362
+ # Pinned, not `@stable`. The Go job pins 1.22 and the Python job
363
+ # pins 3.11 and 3.12, because a toolchain that moves under a green
364
+ # run is a promise nobody tested. `@stable` means this job is
365
+ # decided by whatever Rust was released that morning: `Cargo.lock`
366
+ # pins the CRATES, but never the COMPILER that builds them, so a
367
+ # stranger who clones this repository in six months would be the
368
+ # first person ever to run the contract against a Rust nobody has
369
+ # run it against. 1.99.1 is the toolchain this contract is built
370
+ # and tested against -- it is the current stable today
371
+ # (rustc 1.99.1, 58cf8f9c3) and `cargo test --locked` passes 21/21
372
+ # on it from a clean checkout with no `target/` directory.
373
+ - uses: dtolnay/rust-toolchain@1.99.1
374
+ - name: Contract tests
375
+ working-directory: contracts/fkyh-registry
376
+ run: cargo test --locked