Skip to content

feat(config): security.signing_mode + spiffe config (proposal 011 PR-1) - #81

Merged
flg77 merged 1 commit into
mainfrom
spiffe/config-surface
May 15, 2026
Merged

feat(config): security.signing_mode + spiffe config (proposal 011 PR-1)#81
flg77 merged 1 commit into
mainfrom
spiffe/config-surface

Conversation

@flg77

@flg77 flg77 commented May 15, 2026

Copy link
Copy Markdown
Owner

Summary

Foundational PR for proposal 011 — SPIFFE workload identity for ACC agents. Inert by design: zero behaviour change in v0.4.x because every deploy_mode still defaults to signing_mode: ed25519. PR-2 through PR-5 of proposal 011 (and proposal 012 for edge) consume these fields; v0.5.0 flips the rhoai default to spiffe.

What's new

  • SpiffeConfig Pydantic model with 5 fields, all defaulting to inert values.
  • SecurityConfig gains signing_mode: ed25519 | spiffe | auto (default auto) plus an attached SpiffeConfig block. Existing arbiter_verify_key field is untouched.
  • _SIGNING_MODE_BY_DEPLOY_MODE resolver table — every entry is ed25519 in v0.4.x. v0.5.0 flips the rhoai row.
  • _resolve_signing_mode model-validator replaces auto with the per-deploy_mode default at validation time. Idempotent.
  • Six env-var overrides: ACC_SIGNING_MODE, ACC_SPIFFE_ENABLED, ACC_SPIFFE_TRUST_DOMAIN, ACC_SPIFFE_SVID_MOUNT_PATH, ACC_SPIFFE_JWT_AUDIENCE, ACC_SPIFFE_ALLOW_ED25519_FALLBACK.
  • TUI Configuration screen surfaces resolved values read-only:
    Signing mode: ed25519 (spiffe.enabled=no; proposal 011).

Test plan

  • 15 new tests in tests/test_config.py::TestSpiffeDefaults:
    • Inert defaults
    • Per-deploy_mode resolution (standalone / edge / rhoai → ed25519 in v0.4.x)
    • Explicit spiffe / ed25519 preserved across deploy modes
    • Invalid signing_mode rejected
    • Env-var roundtrip for signing_mode, spiffe.enabled, spiffe.trust_domain, allow_ed25519_fallback
    • Existing arbiter_verify_key still works (backwards compat)
    • Meta-test: every DeployMode value has an entry in _SIGNING_MODE_BY_DEPLOY_MODE (fails if a future deploy_mode is added without updating the resolver)
  • 96/96 green combining config + Configuration pilot + TUI screens
  • +307 / -0 LOC across 5 files (budget 800)
  • Reviewer: confirm resolver table matches proposal 011 §4

Proposal 011 reference

Vault path: 011 - SPIFFE workload identity for ACC agents.md. Status: Proposed.

Stacking PR-1 of proposal 012 (edge extension of this surface) immediately after — both PR-1s land together for review, but split for git history.

🤖 Generated with Claude Code

Foundational PR for proposal 011 — SPIFFE workload identity.
Inert by design: zero behaviour change in v0.4.x because every
deploy_mode still defaults to signing_mode: ed25519.  PR-2..PR-5
of proposal 011 + proposal 012 (edge extension) consume these
fields; v0.5.0 flips the rhoai default to spiffe.

Changes:

* New SpiffeConfig Pydantic model with 5 fields (enabled,
  trust_domain, svid_mount_path, jwt_audience,
  allow_ed25519_fallback).  All default to "inert" — operator
  must opt in explicitly.
* SecurityConfig gains signing_mode: Literal["ed25519",
  "spiffe", "auto"] = "auto" plus an attached SpiffeConfig.
  Existing arbiter_verify_key field unchanged.
* _SIGNING_MODE_BY_DEPLOY_MODE resolver table — every deploy_mode
  defaults to ed25519 in v0.4.x.  Centralised so the resolution
  rule is observable + testable (mirrors proposal 010's
  _ROLE_SOURCE_BY_DEPLOY_MODE pattern).
* New _resolve_signing_mode model-validator replaces "auto" with
  the resolved value at validation time.  Idempotent — explicit
  ed25519 / spiffe pass through unchanged.
* Six env-var overrides: ACC_SIGNING_MODE, ACC_SPIFFE_ENABLED,
  ACC_SPIFFE_TRUST_DOMAIN, ACC_SPIFFE_SVID_MOUNT_PATH,
  ACC_SPIFFE_JWT_AUDIENCE, ACC_SPIFFE_ALLOW_ED25519_FALLBACK.
  Bool values coerced from "true"/"false" strings by Pydantic.
* TUI Configuration screen surfaces resolved values read-only —
  one new line under the existing Role-sync label:
  "Signing mode: ed25519 (spiffe.enabled=no; proposal 011)".

Test coverage: 15 new tests in
tests/test_config.py::TestSpiffeDefaults covering inert defaults,
per-deploy-mode resolution (standalone/edge/rhoai), explicit
overrides preserved, invalid-value rejection, env-var roundtrip
for all four configurable fields, backwards compat (existing
arbiter_verify_key still works), and a meta-test that fails if a
future deploy_mode lands without updating the resolver table.

Plus 1 assertion added to the existing Configuration pilot test
that the new "Signing mode" label is rendered.

Total: +307 / -0 LOC across 5 files.  Well under the 800-LOC PR
budget.  Risk: low — additive field with safe default, no
existing caller broken.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@flg77
flg77 merged commit 784fb8b into main May 15, 2026
@flg77
flg77 deleted the spiffe/config-surface branch May 15, 2026 06:59
flg77 added a commit that referenced this pull request May 15, 2026
Extends proposal 011 PR-1's SpiffeConfig with the 11 edge-specific
fields from proposal 012 §5 step 1 + the three cross-field
validators that fall out of operator's §8 answers (Q1-Q6,
resolved 2026-05-15).

Inert by design: every deploy_mode still defaults to
signing_mode: ed25519 in v0.4.x, so the new fields are read but
not consumed.  012 PR-2..PR-4 wire the actual SPIRE manifests +
agent-side bundle cache + federation handshakes.

New SpiffeConfig fields:

  edge_topology              nested | federated | ed25519
  edge_site_id               operator-supplied (Q5)
  parent_spire_url           required for nested
  federation_peers           required for federated
  offline_bundle_cache_path  default /run/spire/cache/bundle.pem
  offline_max_age_h          default 72.0
  bundle_refresh_h           default 6.0  (Q1)
  offline_action             rotate | degrade | shutdown  (Q2)
  parent_unreachable_action  block | degrade              (Q4)
  nats_mtls_cert_path        Ed25519 fallback path        (Q6)
  nats_mtls_key_path         Ed25519 fallback path        (Q6)

New ACCConfig validator _validate_edge_spiffe_fields enforces
topology-specific requirements only when:

  - deploy_mode == "edge" AND
  - spiffe.enabled == True AND
  - signing_mode == "spiffe"  (operator actually consuming SPIFFE)

Three rules:

  1. nested needs parent_spire_url + edge_site_id
  2. federated needs >= 1 federation_peers entry
  3. offline_action=rotate requires edge_topology=nested

Non-edge deployments + edge with signing_mode=ed25519 pass
through the validator without raising — edge fields stay
advisory.

Nine new env-var overrides for the scalar edge fields.
federation_peers (list type) stays YAML-only since _apply_env
writes scalar strings.

Test coverage: 19 new tests in
tests/test_config.py::TestSpiffeEdgeDefaults covering defaults,
every cross-field validator path (nested missing fields,
federated missing peers, rotate requires nested), non-edge
topology skip for all three deploy_modes, all happy paths,
env-var roundtrip on every scalar override, and invalid-value
rejection for the two new Literal types.

Combined with 011 PR-1's 15 tests: 76/76 green on
tests/test_config.py.

Stacked on top of spiffe/config-surface (011 PR-1, PR #81).

Total: +447 / -0 LOC across 3 files.  Well under the 800-LOC
budget.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
flg77 added a commit that referenced this pull request May 15, 2026
Extends proposal 011 PR-1's SpiffeConfig with the 11 edge-specific
fields from proposal 012 §5 step 1 + the three cross-field
validators that fall out of operator's §8 answers (Q1-Q6,
resolved 2026-05-15).

Inert by design: every deploy_mode still defaults to
signing_mode: ed25519 in v0.4.x, so the new fields are read but
not consumed.  012 PR-2..PR-4 wire the actual SPIRE manifests +
agent-side bundle cache + federation handshakes.

New SpiffeConfig fields:

  edge_topology              nested | federated | ed25519
  edge_site_id               operator-supplied (Q5)
  parent_spire_url           required for nested
  federation_peers           required for federated
  offline_bundle_cache_path  default /run/spire/cache/bundle.pem
  offline_max_age_h          default 72.0
  bundle_refresh_h           default 6.0  (Q1)
  offline_action             rotate | degrade | shutdown  (Q2)
  parent_unreachable_action  block | degrade              (Q4)
  nats_mtls_cert_path        Ed25519 fallback path        (Q6)
  nats_mtls_key_path         Ed25519 fallback path        (Q6)

New ACCConfig validator _validate_edge_spiffe_fields enforces
topology-specific requirements only when:

  - deploy_mode == "edge" AND
  - spiffe.enabled == True AND
  - signing_mode == "spiffe"  (operator actually consuming SPIFFE)

Three rules:

  1. nested needs parent_spire_url + edge_site_id
  2. federated needs >= 1 federation_peers entry
  3. offline_action=rotate requires edge_topology=nested

Non-edge deployments + edge with signing_mode=ed25519 pass
through the validator without raising — edge fields stay
advisory.

Nine new env-var overrides for the scalar edge fields.
federation_peers (list type) stays YAML-only since _apply_env
writes scalar strings.

Test coverage: 19 new tests in
tests/test_config.py::TestSpiffeEdgeDefaults covering defaults,
every cross-field validator path (nested missing fields,
federated missing peers, rotate requires nested), non-edge
topology skip for all three deploy_modes, all happy paths,
env-var roundtrip on every scalar override, and invalid-value
rejection for the two new Literal types.

Combined with 011 PR-1's 15 tests: 76/76 green on
tests/test_config.py.

Stacked on top of spiffe/config-surface (011 PR-1, PR #81).

Total: +447 / -0 LOC across 3 files.  Well under the 800-LOC
budget.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
flg77 added a commit that referenced this pull request Jun 15, 2026
0.2.0 rolls up the RHOAI-maturity wave merged to main today:
- #79 agent podspec SCC-compatible (drops pinned runAsUser:1001) →
  unblocks agent pods on OpenShift restricted-v2 (the 0-agent-pods finding)
- #80 AccPackageInstall execs `python3 -m acc.cli` → fixes pack infusion
  (bare acc-cli console script is not on the non-login kubectl-exec $PATH)
- #76 CollectiveStatus.SharedModel surfacing ("model: shared from acc-system")
- #75 assistant concierge default-injection + hybrid role-catalogue validation
- #74 acc-webgui (Keycloak OIDC) + acc-tui — spec.webgui/spec.tui instantiable

CSV name/version → v0.2.0, replaces v0.1.6, image refs → :0.2.0. acc1 builds
the image + bundle + index (FROM_INDEX 0.1.6) and redeploys on sandbox1154 to
clear the agent pods and the pack-install failures.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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