Repository navigation
evidence(OMN-18081): union-resolve — bind the server half, omninode_infra#1280 - #8805
Merged
Merged
Conversation
…nfra#1280 The operator clarified the intent at ~14:27Z: "It seems like the input is fine but it should be for the label for the API key so that people can mint more than one API key." That reframes OMN-18081 from "the input is missing" (it was not) to "can a customer actually hold several labelled keys", and the ticket's scope item 3 asked the SERVER to be read rather than assumed. Three suspects, one real. There is no per-tenant key cap — MAX_API_KEY_LIMIT is a pagination bound enforced in list_api_keys, not in the mint. Nothing on the create path revokes or replaces an incumbent. So a key with a DISTINCT label was never blocked, which is the headline intent and already worked. The third was real. uq_tenant_api_keys_tenant_id_name_active correctly refuses a second ACTIVE key under the same name, but that refusal reached the customer as a bare 500: it raised ApiKeyValidationError, the router caught nothing, and there is no add_exception_handler for any ApiKeyError in the service, so omniweb rendered its no-detail fallback. omninode_infra#1280 makes it a typed 409. Appended, never edited — and verified empirically rather than asserted. The two existing entries' contract_entry_sha256 values were recomputed after the append AND after the yaml hook's reflow of the new entry, and both are byte-identical to the values already carried by the receipts merged on this branch. That is the append-stability OMN-13888 exists for, and the reflow is exactly the case the per-entry hash is defined over parsed YAML to survive. The new receipts' whole-file contract_sha256 is recomputed for the post-reflow bytes. The older receipts' copies of that field are now stale, which is harmless and expected: it is only ever the FALLBACK, consulted when a receipt carries no entry hash, and both of those carry one. Union-resolve on the same ticket, as OCC#8760 did for omninode_infra#1266: autobind is not minting companions in this window (OMN-18073), so both halves of OMN-18081 bind here rather than to two companions that would collide on the same contract path. Both receipts carry real probe output, run at c911a5d0. AC4c and the staging readback are deliberately NOT bound — they cannot be proven before this merges and reaches onex-dev. No credential was rotated, re-issued, revoked or minted; no secret value was read or printed; no cluster object was mutated.
The eligibility gate refused with reason=missing_occ_self_bind, and it was right: it verified every receipt and every hash binding for OMN-18081, then found no receipt binding to THIS evidence PR. A companion that cannot resolve a PASS receipt for itself is not admissible, whatever it proves about the product PR. A SECOND self-bind exists because OCC#8800 merged before the server half of this ticket was written, so OMN-18081's two halves arrive on two evidence PRs rather than one. occ-self-bind-pr-8800 is left exactly as merged and keeps its own per-entry hash. Whole-file contract_sha256 is refreshed on the three receipts THIS branch owns. The two inherited from #8800 keep their merged bytes untouched: their binding is contract_entry_sha256, whole-file is only the fallback consulted when a receipt carries no entry hash, and rewriting a merged receipt to chase a fallback field would be editing evidence rather than adding it. yamlfmt was run BEFORE the hashes were computed rather than after, so the committed bytes are the formatted bytes and the whole-file hash cannot be stale the moment it lands. All four pre-existing per-entry hashes were recomputed after the reflow and are byte-identical, which is the property the per-entry hash is defined over parsed YAML to have. No credential was rotated, re-issued, revoked or minted; no secret value was read or printed; no cluster object was mutated.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
OCC companion for
OmniNode-ai/omninode_infra#1280— the server half ofOMN-18081, bound by hand (union-resolve) onto the same ticket contract that
OCC#8800 established for the omniweb half.
OCC#8800 merged while this was being written, so this appends to the contract on
devrather than to that PR's branch. Hand-minted because autobind is notproducing companions in this window (OMN-18073).
Why there is a server half at all
OMN-18081 opened stating "no
omninode_infrachange is needed". The operatorthen clarified the intent, in-session 2026-09-09T~14:27Z:
That reframed the ticket from "the label input is missing" (it was not) to "can a
customer actually hold several labelled keys", and the rewritten scope asked the
gateway to be read rather than assumed. Three suspects; one was real.
MAX_API_KEY_LIMITis a pagination bound enforced inlist_api_keys, not in the mint._ensure_default_api_keyreturns early when the tenant holds any key; the mint's body is a singleINSERT.(tenant_id, name)refusing a duplicate labelA key with a distinct label was never blocked by any of the three — the
headline intent already worked. But
uq_tenant_api_keys_tenant_id_name_active'scorrect refusal of a duplicate reached the customer as a bare 500: it raised
ApiKeyValidationError, the router caught nothing, and there is noadd_exception_handlerfor anyApiKeyErrorin the service, so omniweb renderedits no-detail fallback.
#1280makes it a typed 409 with a customer-readablesentence.
Contract change
Appended, never edited, and verified empirically rather than asserted: the
existing entries'
contract_entry_sha256values were recomputed after the append(and after the yaml hook's reflow of the new entry) and are byte-identical to the
values already carried by the merged receipts. That is precisely the
append-stability OMN-13888 exists for, and the reflow is the case the per-entry
hash is defined over parsed YAML to survive.
The new receipts' whole-file
contract_sha256is computed for the current bytes.The older receipts' copies of that field are now stale, which is harmless and
expected — it is only ever the FALLBACK, consulted when a receipt carries no
entry hash, and both of those carry one.
Receipts
Both carry real probe output, run at
c911a5d071f45f189383c9243d2a436896e778fd:command—#1280open onOmniNode-ai/omninode_infra.test_passes— 9/9 intest_omn_18081_duplicate_key_label_refusal.py.RED baseline at
origin/devc6f20f78: 4 of 9 fail. The other 5 pass atbaseline by design — they assert the two absences above, which were already
true and which the ticket asked to verify rather than assume. Each carries a
positive control, so a zero is a fact about the code and not a mis-spelled
probe.
Regression control: the six neighbouring suites were run before and after and
their failure sets diffed — pre-existing env-dependent failures unchanged, zero
new failures. No stderr was suppressed on any probe.
Not bound here
AC4c and the staging readback on
onex-dev. They cannot be proven before#1280merges and reaches the cluster, and binding them now would be a receipt for work
that has not happened.
Rule 24, stated rather than implied: the
.201compose dev lane runs noonex-apiand no dashboard, so there is no lab surface for this path. No lab passis claimed. The staging readback is the proof.
No credential was rotated, re-issued, revoked or minted; no secret value was read
or printed; no cluster object was mutated.
Ticket: OMN-18081
Evidence-Ticket: OMN-18081