Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions control_plane/runtime_key_safety.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ def evaluate_runtime_key_safety(
)
continue
effective_bindings = _effective_bindings_for_target(bindings, target=target)
if not effective_bindings:
findings.append(
RuntimeKeySafetyFinding(
code="binding_missing",
binding_key=binding_key,
detail=f"Required managed secret binding {binding_key!r} is missing.",
)
)
continue
if len(effective_bindings) > 1:
findings.append(
RuntimeKeySafetyFinding(
Expand Down Expand Up @@ -197,11 +206,16 @@ def _bindings_by_binding_key(
def _effective_bindings_for_target(
bindings: tuple[SecretBinding, ...], *, target: RuntimeKeySafetyTarget
) -> tuple[SecretBinding, ...]:
highest_rank = max(_binding_route_rank(binding=binding, target=target) for binding in bindings)
ranked_bindings = tuple(
(binding, _binding_route_rank(binding=binding, target=target)) for binding in bindings
)
highest_rank = max(rank for _, rank in ranked_bindings)
if highest_rank == 0:
return ()
return tuple(
binding
for binding in bindings
if _binding_route_rank(binding=binding, target=target) == highest_rank
for binding, rank in ranked_bindings
if rank == highest_rank
)


Expand Down
31 changes: 26 additions & 5 deletions control_plane/workflows/generic_web_preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,23 @@ def _copied_secret_shaped_runtime_keys(
return tuple(dict.fromkeys(copied_keys))


def _retarget_secret_bindings_for_preview_safety(
*,
secret_bindings: tuple[SecretBinding, ...],
preview_context: str,
preview_slug: str,
) -> tuple[SecretBinding, ...]:
return tuple(
binding.model_copy(
update={
"context": preview_context,
"instance": preview_slug,
}
)
for binding in secret_bindings
)


def _enforce_preview_copied_runtime_key_safety(
*,
record_store: GenericWebPreviewProfileStore,
Expand Down Expand Up @@ -859,11 +876,15 @@ def _enforce_preview_copied_runtime_key_safety(
environment_class="preview",
),
required_binding_keys=required_binding_keys,
secret_bindings=record_store.list_secret_bindings(
integration=control_plane_secrets.RUNTIME_ENVIRONMENT_SECRET_INTEGRATION,
context_name=template_lane.context,
instance_name=template_lane.instance,
limit=None,
secret_bindings=_retarget_secret_bindings_for_preview_safety(
secret_bindings=record_store.list_secret_bindings(
integration=control_plane_secrets.RUNTIME_ENVIRONMENT_SECRET_INTEGRATION,
context_name=template_lane.context,
instance_name=template_lane.instance,
limit=None,
),
preview_context=profile.preview.context,
preview_slug=preview_slug,
),
secret_rules=policy_record.rules,
)
Expand Down
32 changes: 27 additions & 5 deletions control_plane/workflows/verireel_preview_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from control_plane.dokploy import JsonObject
from control_plane.contracts.runtime_identity import RuntimeIdentity, runtime_identity_env
from control_plane.contracts.runtime_key_safety_policy import RuntimeKeySafetyTarget
from control_plane.contracts.secret_record import SecretBinding
from control_plane.runtime_key_safety import (
RuntimeKeySafetyPolicyReadStore,
evaluate_runtime_key_safety,
Expand Down Expand Up @@ -357,6 +358,23 @@ def _verireel_template_runtime_secret_keys(
return tuple(dict.fromkeys(required_keys))


def _retarget_secret_bindings_for_preview_safety(
*,
secret_bindings: tuple[SecretBinding, ...],
preview_context: str,
preview_slug: str,
) -> tuple[SecretBinding, ...]:
return tuple(
binding.model_copy(
update={
"context": preview_context,
"instance": preview_slug,
}
)
for binding in secret_bindings
)


def _enforce_verireel_preview_runtime_key_safety(
*,
record_store: RuntimeKeySafetyPolicyReadStore | None,
Expand Down Expand Up @@ -385,11 +403,15 @@ def _enforce_verireel_preview_runtime_key_safety(
environment_class="preview",
),
required_binding_keys=required_binding_keys,
secret_bindings=record_store.list_secret_bindings(
integration=control_plane_secrets.RUNTIME_ENVIRONMENT_SECRET_INTEGRATION,
context_name=template_target.context,
instance_name=template_target.instance,
limit=None,
secret_bindings=_retarget_secret_bindings_for_preview_safety(
secret_bindings=record_store.list_secret_bindings(
integration=control_plane_secrets.RUNTIME_ENVIRONMENT_SECRET_INTEGRATION,
context_name=template_target.context,
instance_name=template_target.instance,
limit=None,
),
preview_context=request.context,
preview_slug=request.preview_slug,
),
secret_rules=policy_record.rules,
)
Expand Down
29 changes: 29 additions & 0 deletions tests/test_runtime_key_safety.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,35 @@ def test_more_specific_binding_satisfies_target_when_context_binding_also_exists
self.assertEqual(evaluation.status, "pass")
self.assertEqual(evaluation.findings, ())

def test_unrelated_context_binding_does_not_satisfy_target(self) -> None:
evaluation = evaluate_runtime_key_safety(
target=RuntimeKeySafetyTarget(
context="opw",
instance="prod",
environment_class="prod",
),
required_binding_keys=("ODOO_ADMIN_PASSWORD",),
secret_bindings=(
_binding(
binding_key="ODOO_ADMIN_PASSWORD",
binding_id="binding-cm-admin-password",
secret_id="secret-cm-admin-password",
).model_copy(update={"context": "cm", "instance": "prod"}),
),
secret_rules=(
RuntimeSecretSafetyRule(
binding_key="ODOO_ADMIN_PASSWORD",
secret_class="shared_safe",
allowed_contexts=("cm", "opw"),
allowed_instances=("testing", "prod"),
),
),
)

self.assertEqual(evaluation.status, "fail")
self.assertEqual(evaluation.findings[0].code, "binding_missing")
self.assertEqual(evaluation.findings[0].binding_key, "ODOO_ADMIN_PASSWORD")

def test_equally_specific_duplicate_bindings_remain_ambiguous(self) -> None:
evaluation = evaluate_runtime_key_safety(
target=RuntimeKeySafetyTarget(
Expand Down