Skip to content

SECURITY: a plane never receives a credential's bytes (credential-field refs, template refs); a member's env resolves at spawn - #684

Closed
MattJackson wants to merge 3 commits into
p6-k1-stripfrom
sec-plane-secret-refs-p1b
Closed

MattJackson wants to merge 3 commits into
p6-k1-stripfrom
sec-plane-secret-refs-p1b

Conversation

@MattJackson

@MattJackson MattJackson commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

SECURITY: a plane never receives a credential's bytes; a member's env resolves at spawn

Stacked on P1b (#670, merged into this base). It reworks sec-plane-secret-refs (2393666, predev-based) to the SECURITY rulings of 2026-10-07:

  • a SecretRef is used only for CREDENTIAL fields;
  • url, command, args, cwd and token_url keep load-time interpolation, so nothing 1.5.5 accepted is narrowed;
  • a credential filled only in part becomes a TEMPLATE reference;
  • a member's env resolves at the SPAWN.

Why

${VAR} is spliced into the config text before it is parsed, so every door plane was handed interpolated plaintext in its open settings, its refresh settings and its owned blob. P1b measured this (Latchkey cli-d43752e9).

What

  • busbar-kernel config::filled:
    • The interpolation's structural check already walks the real and placeholder trees in step. It now records each scalar ${VAR} filled: the path, the variables, whole or part, the value as written, and a per-process keyed digest. It never records the value.
    • plane_bound replaces a value only at a CREDENTIAL position, and only while the value keeps its digest. A credential position is any of:
      • a credential key: api_key, token, access_token, refresh_token, id_token, client_secret, subject_token, secret, password, passphrase, private_key, authorization, bearer;
      • an entry of an env map;
      • anything inside upstream_credentials.
    • A whole value becomes { env: VAR }. A part becomes { module: template, settings: { text: "Bearer ${VAR}" } }. Every other position crosses as interpolated, and nothing is refused.
  • Bound blobs: the door's validate settings and facing probe, DoorOwned::bytes, the stage-3g validate blob of a plane's verb sections, and serve.rs crossed (open and both refresh paths) plus the owned sections.
  • busbar-contract:
    • SecretRef::template / template_text / resolve_template (SECRET_MODULE_TEMPLATE);
    • Program::secret_env holds a program's env references as references.
  • busbar-core-connector: install_spawn_secrets. Connection::spawn resolves secret_env there and nowhere earlier, filling each ${VAR} of a template in place. A reference that does not resolve refuses the spawn, naming the variable and its source, never a value.
  • plugin-loader: member_programs no longer resolves env at the declare (MemberSecretFn and install_member_secrets are removed). The root installs the linked secret resolver into the connector instead.
  • The kernel's SECRET_BEARING_TYPES inventory accounts for Program.

Proof (Latchkey cli-088f9f23-2f50-48b1-b50f-6528ad04dbca, head 9d3fa66, before the inventory commit)

  • fmt and clippy (-p busbar-contract -p busbar-core-connector -p busbar-kernel -p busbar-plugin-loader -p busbar --all-targets -D warnings): clean. Examples built.
  • RED, plane_bound handing every blob as interpolated (the base), FAILED:
    • root planes_tests::an_interpolated_credential_reaches_a_door_plane_as_its_reference_never_its_bytes;
    • kernel config::filled (6 cells).
  • GREEN:
    • the root cell, and P1b's a_door_planes_open_and_refresh_carry_no_reserved_key, pass;
    • cargo test -p busbar-contract, -p busbar --bin busbar, -p busbar-plane-mcp -p busbar-plane-llm -p busbar-plane-decisions: 0 failed;
    • cargo test -p busbar-core-connector: lib green, including a_members_secret_environment_resolves_at_the_spawn and a_member_whose_secret_environment_does_not_resolve_is_not_spawned. The one red is the known environment red tests/universal_needs.rs: the pinned framer cdylib only the hop builds.
    • cargo test -p busbar-kernel, every target green except:
      • secret_ref_coverage::every_secret_bearing_type_is_accounted_for, fixed in 959ef54 (the inventory row for Program);
      • base's known red root_key_spelling, which goes green with DEL.
    • cargo test -p busbar-plugin-loader: 612 passed, 2 failed. The two are the known environment reds at both_ways.rs: the external pinned secret-env twin is not built.
  • The spawn RED arm did not compile in that job. Under the 2026-10-08 rule (the PR's hop is the proof) it was not re-run.

Customer-visible

  • A credential ${VAR} reaches a plane as a reference rather than its bytes. Planes resolve no credential themselves; the kernel and host do.
  • url, command, args, cwd and token_url are unchanged from 1.5.5.
  • A member's environment reference now resolves at each spawn rather than at the declare: a rotated secret is picked up on the next spawn.

…} filled crosses as its secret reference; a member's env resolves at spawn

SECURITY rulings (2026-10-07):
- a SecretRef only at a credential field;
- url, command, args, cwd and token_url keep load-time interpolation (no 1.5.5 narrowing);
- a credential filled in part is a template reference;
- a member's env resolves at the spawn.
Stacked on P1b (p6-k1-open-strip): every crossing it routes through the deal's one strip is bound
here too.

- busbar-kernel config::filled. The interpolation's structural check walks the real and placeholder
  trees in step; it records each scalar `${VAR}` filled. A record holds the path, the variables,
  whole or part, the value as written and a per-process keyed digest; it never holds the value.
- plane_bound replaces a value only at a CREDENTIAL position, and only while the value keeps its
  digest. A credential position is any of:
  - a credential key (api_key, token, client_secret, subject_token, password, secret, private_key,
    authorization, bearer, and the other token names);
  - an entry of a program's `env` map;
  - anything inside the kernel-owned `upstream_credentials` block.
  A whole value becomes `{ env: VAR }`. A part becomes a template reference
  (`{ module: template, settings: { text: "Bearer ${VAR}" } }`). Every other position crosses as
  interpolated. Nothing is refused.
- Bound blobs: the door's validate settings and facing probe, DoorOwned::bytes, the stage-3g
  validate blob of a plane's verb sections, and serve.rs `crossed` (open and both refresh paths)
  plus the owned sections.
- busbar-contract:
  - SecretRef::template / template_text / resolve_template (SECRET_MODULE_TEMPLATE);
  - Program::secret_env holds a program's `env` references as references.
- busbar-core-connector: install_spawn_secrets. Connection::spawn resolves `secret_env` there and
  nowhere earlier, a template's every `${VAR}` filled in place. A reference that does not resolve is
  refused, naming the variable and the source, never a value.
- plugin-loader: member_programs no longer resolves `env` at the declare (MemberSecretFn and
  install_member_secrets removed). The root installs the linked secret resolver into the connector
  instead.

REDs:
- root planes_tests `an_interpolated_credential_reaches_a_door_plane_as_its_reference_never_its_bytes`;
- kernel filled_tests;
- connector `a_members_secret_environment_resolves_at_the_spawn` and
  `a_member_whose_secret_environment_does_not_resolve_is_not_spawned`;
- contract `a_template_reference_resolves_each_variable_in_place` and
  `a_programs_secret_environment_is_held_as_its_reference`.
…gram resolved at the spawn, not a RootCfg type
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

promote into p6-k1-strip: NO VERDICT @959ef5405

The hop ended without writing a verdict (runner lost, timeout, cancel, or it died before the engine judged): preflight: failure at step Run cargo run --locked --release --no-default-features -p busbar-release-cli --bin busbar-release -- ci preflight; publish: runner lost at step Run bash "$GITHUB_WORKSPACE/busbar-release/ci/promote/fallback.sh", Post Run actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1.

No failing-test list exists for this run. Run: https://github.com/GetBusbar/busbar/actions/runs/37722031828 . Re-run the hop, or read the job's step list in the run page.

@MattJackson

Copy link
Copy Markdown
Collaborator Author

Superseded by #727: the SECURITY change carried onto predev. P1b is not on predev, so #727 binds the crossings predev has (handed_settings for open and refresh, the door's settings_of, DoorOwned::bytes, the owned sections, the stage-3g blob). Branch bundled at ~/Library/Caches/busbar-release/salvage/GetBusbar_busbar-sec-plane-secret-refs-p1b-1791610783.bundle and deleted.

@MattJackson
MattJackson deleted the sec-plane-secret-refs-p1b branch October 10, 2026 06:11
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