Skip to main content

PolicyRules

Struct PolicyRules 

Source
pub struct PolicyRules {
    pub max_lifetime_ttl_seconds: Option<u64>,
    pub max_memory_max_bytes: Option<u64>,
    pub max_run_timeout_ms: Option<u64>,
    pub require_egress_declared: bool,
    pub forbid_outbound_egress_rules: bool,
    pub allowed_egress_hosts: Vec<String>,
    pub require_runtime_secret_delivery: bool,
    pub require_resource_limits: bool,
    pub flag_dns_egress_without_acknowledgment: Option<bool>,
    pub require_dns_egress_justification: Option<bool>,
    pub secret_ref_allowlist: Option<HashMap<String, Vec<String>>>,
}
Expand description

Constraint rules within a policy pack.

All fields are optional — an absent field means “no restriction on this axis.” A PolicyPack with an empty PolicyRules is valid but does not constrain any spec (useful as an explicit “audit-only” marker).

Fields§

§max_lifetime_ttl_seconds: Option<u64>

spec.lifetime.ttlSeconds must not exceed this value.

§max_memory_max_bytes: Option<u64>

spec.run.limits.memoryMaxBytes must not exceed this value.

§max_run_timeout_ms: Option<u64>

spec.run.timeoutMs must not exceed this value.

§require_egress_declared: bool

When true, spec.authority.egressRules must be non-empty.

Use this to force explicit declaration of all outbound network intent — specs that declare no egress rules are rejected.

§forbid_outbound_egress_rules: bool

When true, specs must declare zero outbound egress rules.

Use this to enforce fully air-gapped workloads. A spec with any spec.authority.egressRules is rejected.

§allowed_egress_hosts: Vec<String>

When non-empty, every spec.authority.egressRules[].host must match at least one pattern in this list.

Patterns support a single leading *. wildcard (e.g. *.internal). Exact hostnames are also accepted. An empty list means no restriction.

§require_runtime_secret_delivery: bool

When true, spec.run.secretDelivery must not be env.

Use this to prohibit the default env-variable secret delivery mode and require runtimeBroker or runtimeLeasedBroker instead.

§require_resource_limits: bool

When true, spec.run.limits must be present.

Use this to ensure every spec explicitly declares resource bounds.

§flag_dns_egress_without_acknowledgment: Option<bool>

When true, any spec that declares an egress rule on port 53 (DNS) is flagged with a PolicyViolation unless the spec also sets authority.egressRules[].protocol = "dns-acknowledged" on every port-53 rule.

CellOS’s egress policy operates at L3/L4 (IP:port via nftables) and has no visibility into DNS query content. A cell with declared port 53 egress can therefore exfiltrate arbitrary data via DNS TXT query labels to an attacker-controlled authoritative nameserver, completely outside CellOS observability. See docs/sec_roadmap.md R10 / SEC-15.

The dns-acknowledged protocol value is a forcing function, not a security control: operators who understand the covert-channel risk can set it to suppress the violation. Future work (L2-04 extension) is a DNS proxy inside the cell netns with query-level CloudEvents.

§require_dns_egress_justification: Option<bool>

When true, any port-53 egress rule with protocol = "dns-acknowledged" must also supply a non-empty dnsEgressJustification string.

This closes SEAM-2 (illusory consent): without it, an operator can suppress flag_dns_egress_without_acknowledgment by typing four words and zero further effort, defeating the forcing function. With the rule enabled, the operator must record an auditable justification alongside the acknowledgment, raising the cost of reflexive suppression and creating evidence of stated reasoning. See docs/sec_roadmap.md R10 / SEC-15c.

§secret_ref_allowlist: Option<HashMap<String, Vec<String>>>

A2-02: per-caller-identity allowlist for spec.authority.secretRefs.

Map shape: caller-identity → [allowed secretRef key]. The caller identity is host-stamped via CELLOS_CALLER_IDENTITY at the supervisor boundary (per ADR-0007 / D11: cellos-core itself does NOT read process env vars; the resolved identity is threaded through to validate_secret_refs_against_allowlist as a parameter).

When this field is None, the allowlist gate is skipped entirely — admission proceeds against the rest of the rules unchanged. This is the “audit-only” / opt-in posture documented in ADR-0007 §“What 1.0 ships”.

When this field is Some(map):

  • The caller’s identity MUST appear as a key in map (otherwise the caller is “unmapped” and rejected with CellosError::InvalidSpec carrying a caller_unmapped reason string).
  • Every entry in spec.authority.secretRefs MUST appear in map[caller_identity] (otherwise admission is rejected with a secret_ref_denied reason naming the offending key).

The keys (caller identities) and values (secretRef names) are operator- curated portable strings; this field carries no implicit role hierarchy (see ADR-0007 non-goal “Hierarchical roles / role inheritance”). Two callers needing the same set of refs are two map entries, not one.

See ADR-0007 (docs/adr/0007-rbac-secret-ref-admission.md) for the contract; A2-03 (multi-tenant event isolation) is a separate surface.

Trait Implementations§

Source§

impl Clone for PolicyRules

Source§

fn clone(&self) -> PolicyRules

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PolicyRules

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for PolicyRules

Source§

fn default() -> PolicyRules

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for PolicyRules

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for PolicyRules

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,