Skip to content

fix(OMN-20533): dev-lane runtime-effects reads tenant BYOK keys with its own read-only Infisical identity - #4561

Merged
jonahgabriel merged 2 commits into
devfrom
jonah/omn-20439-runtime-effects-tenant-credential-read
Oct 4, 2026
Merged

jonahgabriel merged 2 commits into
devfrom
jonah/omn-20439-runtime-effects-tenant-credential-read

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

What

Closes the BYOK read half on the .201 dev lane (OMN-20533, child of OMN-18829; OMN-20439 landed the write half in #4539).

onex-api writes a tenant's provider key to Infisical env dev, folder /tenant-inference-credentials, under a minted ref, and the tenant overlay routes the lab tenant to it. The provider call runs in runtime-effects, whose resolver config was house-only (env mappings, no namespace rule, blank identity), so every tenant ref failed closed: 4 of 4 lab-tenant runs on 2026-10-04 09:33-09:50Z ended provider_error.

  • contracts/services/runtime_policy.contract.yaml: the tenant_inference_credentials namespace rule on the dev profile's effects process only (same rule and folder as the onex-dev runtime ConfigMap).
  • ModelRuntimeProcessPolicy.secret_resolver_namespaces (new, process-level) plus profile validation (needs the config path, names unique across process and profile).
  • scripts/render_runtime_policy_env.py: renders DEV_RUNTIME_EFFECTS_STORE_SECRET_RESOLVER_CONFIG_JSON (house mappings plus the rule). Every profile-level *_SECRET_RESOLVER_CONFIG_JSON is unchanged.
  • docker-compose.dev-lane.yml runtime-effects: binds that config, INFISICAL_ADDR/PROJECT_ID/CLIENT_ID/CLIENT_SECRET from RUNTIME_EFFECTS_INFISICAL_* host names, slug pinned to dev.
  • docker-compose.dev-105/200/202.yml and docker-compose.prepr.yml: rebind runtime-effects to the house config and the base identity names. An Infisical rule makes a process build its store handler at wiring time and refuse when the identity is blank, and those lanes hold none.

Why not the profile, and why :-

A profile-level rule would reach main, worker and tenant-projection, and each would then demand an identity at boot. The identity is :-, because compose interpolates every file before it merges them, so :? in the shared dev-lane file would fail the borrower lanes' render. On .201 a blank identity is still loud: effects refuses at wiring and names every blank variable (proven below).

Identity (already provisioned, consent ledger OPERATOR-CONSENT 2026-10-04T18:27:06Z lane=byok-infisical)

Instance D, project 872e00f4, identity dev-lane-runtime-effects-tenant-credentials (8940ae51), org role no-access, project role dev-lane-runtime-effects-tenant-cred-read = secrets read on env dev /tenant-inference-credentials only. As the identity, the tenant folder lists 22 names (admin control: 22); /shared/env lists 0 (admin: 6); /lab-provider-keys lists 0 (admin: 1); prod and staging list 0; a create on the tenant path returns 403. The four RUNTIME_EFFECTS_INFISICAL_* names are in the .201 operator env file. Nothing reads them until this merges.

Lab proof (no dev-lane container touched)

An isolated throwaway container ran on .202 (image omnibase-infra-dev-202-runtime-effects sha256:04b92f1c5842, bridge network, removed afterwards) against the real instance D, using this branch's rendered store config. The probe ran at 2026-10-04T18:50:43Z:

mode omnibase_infra build_topology_secret_resolver omnimarket resolve_api_key_with_source_async
store config + identity built, namespace tenant_inference_credentials; lab-tenant ref resolves non-empty (len 73); unregistered ref raises RESOURCE_NOT_FOUND non-empty (len 73), source lane_secret_store
store config, no identity refuses, naming all 5 blank INFISICAL_* refuses, same names
house config (today) tenant ref unresolvable the could-not-be-resolved refusal seen in the 09:33-09:50Z runs

The compose render (docker compose config, non-mutating) shows dev runtime-effects carrying the rule and RUNTIME_EFFECTS_INFISICAL_*, with main and worker unchanged. dev-202 and prepr runtime-effects render house-only, with no client id and a blank slug.

RLS and tenant-form paths: not touched. This reads a credential at the effect boundary. It changes no RLS policy and no reader authorization through onex-api.

Tests

  • tests/integration/infra/test_runtime_effects_tenant_credential_read_omn20533.py: 14 pass. Against the dev pre-image, 12 of the 14 fail.
  • Focused set (runtime policy contract both suites, OMN-16944 namespace surface, dev-lane required env, dev-202/dev-105 lane boundaries, compose required-env coverage, dev runtime compose render): 111 passed, 1 skipped.
  • render_runtime_policy_env.py --check-env-file docker/runtime-policy.env: match.

Deploy note

Runtime-affecting for the .201 dev lane's runtime-effects only. The ledger HOLD keeps it unmerged until 2026-10-05T05:45Z, because a merge triggers a deploy-agent dev-lane recreate and the dev lane is in live demo use until then. The scheduled warm refresh is at 2026-10-05T06:00Z.

Evidence-Ticket: OMN-20533
Evidence-Source: OCC#12832

…its own read-only Infisical identity

The contract declares the tenant_inference_credentials namespace rule on the
dev profile's effects process only, rendered as
DEV_RUNTIME_EFFECTS_STORE_SECRET_RESOLVER_CONFIG_JSON. docker-compose.dev-lane.yml
binds it on runtime-effects with RUNTIME_EFFECTS_INFISICAL_* from the host env
file; the dev-105, dev-200, dev-202 and pre-PR overlays rebind the house-only
config so a lane without the identity never demands one.

Onex-Lane: byok-infisical
Onex-Session: ef2d8921f964462697ccdcd0395cc080
@jonahgabriel
jonahgabriel enabled auto-merge October 4, 2026 18:59
jonahgabriel pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Oct 4, 2026
…12832)

* evidence(OMN-20533): author OCC companion for OmniNode-ai/omnibase_infra#4561

OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 641c37be6525a65f5e440535f9e70a955e1702ea.

* evidence(OMN-20533): self-bind OCC#12832 + rebind contract_sha256

---------

Co-authored-by: omnimarket-bot <bot@omninode.ai>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hostile Reviewer — adversarial findings (OMN-17492)

Models succeeded: qwen3-review, gpt-oss-review
Models failed: none
New finding threads: 0
Deduped (already posted on this PR): 0
Below quorum (one model only, reported not threaded): 11
Nit-level findings suppressed: 0

The model is the FINDER, never the gate: merge is gated only by the
deterministic Hostile Review Thread Gate, which blocks while
hostile-reviewer threads are unresolved. Resolve each thread after
addressing (or rejecting, with a reply) its finding.

Below quorum: 11 finding(s) raised by one model only (OMN-18479)

These are reported and NOT dropped, but they get no thread and do not block: a single model's finding no other model reproduced is not evidence enough to stop a merge. Read them; act on them if they are right.

  • [MAJOR] contracts/services/runtime_policy.contract.yaml (qwen3-review) — Regex allows tenant refs to reference arbitrary paths in Infisical | The ref_pattern ^cred_[A-Za-z0-9._:-]+_[A-Za-z0-9_-]+_[0-9a-f]{32}$ permits the tenant and provider segments to contain dots, col
  • [MAJOR] docker/docker-compose.dev-lane.yml, docker/docker-compose.dev-105.yml, docker/docker-compose.dev-200.yml, docker/docker-compose.dev-202.yml, docker/docker-compose.prepr.yml (qwen3-review) — Infisical client secret exposed in docker-compose environment | The dev-lane and all borrower overlays set INFISICAL_CLIENT_SECRET as a plain environment variable in the docker-compose file. In dev-
  • [MAJOR] docker/docker-compose.dev-105.yml, docker/docker-compose.dev-200.yml, docker/docker-compose.dev-202.yml, docker/docker-compose.prepr.yml (qwen3-review) — Borrower overlays use house config but still set INFISICAL_* env vars | The borrower overlays (dev-105, dev-200, dev-202, prepr) rebind ONEX_SECRET_RESOLVER_CONFIG_JSON to the house-only config (`DE
  • [MAJOR] scripts/render_runtime_policy_env.py (gpt-oss-review) — Empty SECRET_RESOLVER_CONFIG_JSON emitted when no mappings or namespaces | render_runtime_policy_env.render_env sets secret_resolver_config_json to an empty string when a profile has neither secret_re
  • [MINOR] tests/integration/infra/test_runtime_effects_tenant_credential_read_omn20533.py (qwen3-review) — No test for the case where a borrower overlay is missing the rebind | The test test_every_other_dev_lane_layer_rebinds_the_house_config asserts that each borrower overlay sets `ONEX_SECRET_RESOLVER_
  • [MINOR] scripts/render_runtime_policy_env.py (qwen3-review) — Resolver config JSON is re-serialized on every render | The _secret_resolver_config_json function is called for each process that has secret_resolver_namespaces. In the current contract, only the
  • [MINOR] tests/integration/infra/test_runtime_effects_tenant_credential_read_omn20533.py (qwen3-review) — Test does not verify that the house config is not modified | The test test_the_rendered_store_config_is_the_house_config_plus_the_rule asserts that the store config's mappings equal the house config
  • [MINOR] src/omnibase_infra/runtime/models/model_runtime_process_policy.py (qwen3-review) — Process-level namespaces are a new concept that may be confusing | The introduction of secret_resolver_namespaces on the process policy is a new architectural concept. The comment explains that it i
  • [MINOR] src/omnibase_infra/runtime/models/model_runtime_profile_policy.py (gpt-oss-review) — Assumption that secret_resolver_config_path is always a string | ModelRuntimeProfilePolicy._requires_the_runtime_family_and_allows_optional_carriers validates `if not self.secret_resolver_config_path.
  • [MINOR] docker/runtime-policy.env (gpt-oss-review) — Potential information disclosure via env‑exposed secret resolver config | The new DEV_RUNTIME_EFFECTS_STORE_SECRET_RESOLVER_CONFIG_JSON environment variable contains the full secret‑resolver configu
  • [MINOR] docker/docker-compose.dev-105.yml (gpt-oss-review) — Default‑empty INFISICAL_* variables may hide missing identity configuration | Docker compose files for dev‑105, dev‑200, dev‑202, and prepr set INFISICAL_ADDR, INFISICAL_PROJECT_ID, `INFISICAL_CLI

@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

✅ Hostile Reviewer — REVIEWED

Critical findings: 0
Major findings: 4
Total findings: 11
Models succeeded: qwen3-review,gpt-oss-review
Models unavailable: none

Action required: findings were posted as review threads. Address or reject each one, then resolve its thread — the Hostile Review Thread Gate fails while hostile-reviewer threads are unresolved (OMN-17492).


Semantics (OMN-17492 — the model finds, thread resolution gates)

Surface Meaning Blocks merge?
Review threads Per-finding, posted by the reviewer No (informational)
Hostile Review Thread Gate Deterministic: unresolved hostile-reviewer threads exist Fails until resolved (not yet a required context)
degraded verdict Fewer than 2 models succeeded (infra) Fails this job with a named reason

Powered by omniintelligence.review_pairing.cli_review — multi-model adversarial review: qwen3-review (Qwen3.8-27B), gpt-oss-review (gpt-oss-120b) (OMN-8468/OMN-8524/OMN-17492)

@jonahgabriel
jonahgabriel added this pull request to the merge queue Oct 4, 2026
Merged via the queue into dev with commit 3cab249 Oct 4, 2026
182 of 195 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-20439-runtime-effects-tenant-credential-read branch October 4, 2026 19:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant