Q-Trust Plane

QPL

QPL Specification

Deterministic policy-as-code language spec: canonicalization, evaluation semantics, obligations, and stable hashing.

Highlights

  • Default-deny with deny-wins resolution for deterministic outcomes.
  • Canonicalization and stable hashing to make policy bundles signable and auditable.
  • Obligations and evidence requirements as first-class policy outputs.

QPL-SPEC

Q-Trust Plane — QPL (Q-Policy Language) Specification
Doc: Repository-friendly spec (formal, reduced from whitepaper, still complete)
Version: 1.1
Status: Stable draft (implementation-target)
Goal: Deterministic Policy-as-Code for cryptographic governance (Web2 + Web3)


0. Overview

QPL is a deterministic Policy-as-Code language used by Q-Trust Plane to decide whether to issue an ephemeral, single-use grant authorizing a specific action on a resource within strict constraints.

QPL policies:

  • match an action + resource selector
  • evaluate a boolean condition (when)
  • return an effect (allow/deny)
  • can attach obligations, constraints, evidence requirements, and TTL

Hard guarantees:

  • default deny
  • deny-wins resolution
  • deterministic evaluation
  • canonicalization → stable hashing → signing

1. Core Objects (Authorization Request Model)

Policies evaluate a normalized AuthzRequest with the following conceptual structure:

1.1 subject

Represents the requesting identity + bindings:

  • subject.issuer (OIDC issuer)
  • subject.claims.* (repo, workflow, actor, job id, etc.)
  • subject.roles (derived roles)
  • subject.workload.* (runner id, cluster id, agent id)
  • subject.wallet.* (optional factor binding)

1.2 action

String identifier:

  • web3.contract.deploy
  • web3.contract.upgrade
  • web3.bridge.rotate_signers
  • iac.terraform.apply
  • k8s.admission.create_pod
  • secrets.lease.read
  • ml.model.deploy

1.3 resource

Describes target:

  • resource.type (contract/proxy/bridge/terraform/k8s/secret/ml_model)
  • chain selectors:
    • resource.chain.family (evm/cosmos/substrate)
    • resource.chain.id (e.g., ethereum:1)
    • resource.chain.network (mainnet/testnet/custom)
  • infra selectors:
    • resource.env (prod/stage/dev)
    • resource.cluster, resource.namespace
  • identifiers:
    • resource.id, resource.address, etc.

1.4 context

Execution and runtime data:

  • context.time.utc (RFC3339)
  • context.git.branch, context.git.tag, context.git.sha
  • context.pipeline.run_id, context.pipeline.job_id, context.pipeline.url
  • context.artifact.digest (sha256/...)
  • context.change_ticket (enterprise)

1.5 attestations

Verified proofs and metadata:

  • attestations.slsa.present, attestations.slsa.digest, attestations.slsa.verified
  • attestations.sbom.present, attestations.sbom.digest, attestations.sbom.verified
  • attestations.commit.signature_valid
  • attestations.approvals.group, attestations.approvals.count
  • attestations.terraform.plan_signed
  • attestations.model.provenance.present

2. Type System

2.1 Primitive types

  • bool
  • int (signed 64-bit)
  • string (UTF-8)
  • bytes (opaque; base64 in API JSON)
  • time (RFC3339 UTC instant)
  • duration (seconds; source form may include 30s, 5m, 2h)
  • semver (semantic version)
  • cidr
  • hash (typed hash object)

2.2 Composite types

  • list<T>
  • set<T> (unordered unique)
  • map<string,T>
  • object (structured)

2.3 Undefined semantics

  • Missing paths evaluate to undefined
  • Comparisons with undefined evaluate to false
    (except explicit checks via is_defined(x))

3. Operators and Built-ins

3.1 Comparison operators

  • ==, != (same-type only)
  • <, <=, >, >= for int, time, duration, semver
  • in membership:
    • "main" in {"main","release"}
    • subject.issuer in {"issuerA","issuerB"}
  • matches regex operator:
    • context.git.tag matches regex("^v\\d+\\.\\d+\\.\\d+$")

3.2 Boolean operators

  • and, or, not

3.3 String helpers (functions)

  • starts_with(str, prefix) -> bool
  • ends_with(str, suffix) -> bool
  • contains(str, needle) -> bool

3.4 Time helpers (functions)

  • within_time_window(time, "HH:MM", "HH:MM", "TZ") -> bool
  • time_between(t, start_time, end_time) -> bool (optional alias)

3.5 Hash helpers

  • hash(alg, hex_or_b64) -> hash
  • hash_eq(a, b) -> bool (checks alg match + value match)
  • hash_alg(h) -> string

3.6 Defined checks

  • is_defined(x) -> bool
  • coalesce(x, y) -> T

3.7 Resource selector helpers

Used only inside match blocks:

  • glob("pattern")
  • regex("pattern")

4. Formal Grammar (EBNF)


policy_set     = { policy } ;

policy         = "policy" identifier "{"
meta_block
match_block
decision_block
"}" ;

meta_block     = "meta" "{" { meta_entry } "}" ;
meta_entry     = identifier ":" literal ";" ;

match_block    = "match" "{" { match_entry } "}" ;
match_entry    = "action" ":" string ";"
| "resource" ":" resource_selector ";" ;

resource_selector = "{" { resource_field } "}" ;
resource_field = identifier ":" literal_or_pattern ";" ;

literal_or_pattern = literal | pattern ;
pattern        = "regex" "(" string ")" | "glob" "(" string ")" ;

decision_block = "effect" ":" effect ";"
[ "when" ":" expr ";" ]
[ obligations_block ]
[ constraints_block ]
[ evidence_block ]
[ ttl_block ]
;

effect         = "allow" | "deny" ;

obligations_block = "obligations" "{" { obligation_entry } "}" ;
obligation_entry  = identifier ":" obligation_value ";" ;

obligation_value  = literal | object_literal | list_literal ;

constraints_block = "constraints" "{" { constraint_entry } "}" ;
constraint_entry  = identifier ":" literal_or_object ";" ;

literal_or_object = literal | object_literal | list_literal ;

evidence_block = "evidence" "{" { evidence_entry } "}" ;
evidence_entry = identifier ":" literal_or_object ";" ;

ttl_block      = "ttl" ":" duration_literal ";" ;

expr           = or_expr ;
or_expr        = and_expr { "or" and_expr } ;
and_expr       = unary_expr { "and" unary_expr } ;
unary_expr     = [ "not" ] primary ;
primary        = "(" expr ")" | comparison | function_call | boolean_literal ;

comparison     = value comp_op value ;
comp_op        = "==" | "!=" | "<" | "<=" | ">" | ">=" | "in" | "matches" ;

value          = literal | path | function_call | list_literal | set_literal ;

path           = identifier { "." identifier } ;

function_call  = identifier "(" [ arg_list ] ")" ;
arg_list       = value { "," value } ;

literal        = string | int | boolean_literal | time_literal | hash_literal ;
list_literal   = "[" [ value { "," value } ] "]" ;
set_literal    = "{" [ value { "," value } ] "}" ;

object_literal = "{" [ object_entry { "," object_entry } ] "}" ;
object_entry   = identifier ":" value ;

duration_literal = int "s" | int "m" | int "h" ;
time_literal     = "time" "(" string ")" ;
hash_literal     = "hash" "(" string "," string ")" ;


5. Deterministic Evaluation Semantics

5.1 Matching

A policy is candidate iff:

  • match.action == request.action
  • match.resource matches request.resource:
    • exact match for literals
    • glob/regex match for patterns

Resource matching rule: all specified fields must match (logical AND).

5.2 Condition (when)

If when is absent → treated as true.

If any operand is undefined:

  • comparisons → false
  • boolean operators behave normally (false and undefinedfalse; true and undefinedfalse due to undefined comparisons)

5.3 Resolution (deny-wins)

Deterministic resolution:

  1. Evaluate all candidate policies with when == true.
  2. If any policy has effect: deny, DENY.
  3. Else if any policy has effect: allow, ALLOW.
  4. Else DENY.

Rationale: safety-first posture prevents “allow gaps” being exploited.

5.4 Outputs

If ALLOW:

  • obligations + constraints + evidence requirements + TTL are returned
  • these become part of the Grant payload

6. Canonicalization (Hash-Stable Representation)

QPL is designed to be hashed and signed reliably across implementations.

6.1 Canonical Policy Representation (CPR)

Policy is transformed into a canonical object:

  • keys sorted lexicographically
  • sets sorted by canonical ordering
  • durations normalized to seconds
  • time normalized to RFC3339 UTC
  • expressions represented as explicit AST nodes:
    • {"op":"and","args":[...]}
    • {"op":"or","args":[...]}
    • {"op":"not","arg":...}
    • {"op":"cmp","cmp":"==","left":...,"right":...}

6.2 Domain separation

Hashes MUST be domain separated:

  • "QTRUST:POLICY:"
  • "QTRUST:POLICYSET:"
  • "QTRUST:REQUEST:"
  • "QTRUST:GRANT:"
  • "QTRUST:EVIDENCE:"

6.3 Policy hash

  • policy_hash = SHA256("QTRUST:POLICY:" || canonical_policy_bytes)
  • policy_set_hash = SHA256("QTRUST:POLICYSET:" || concat(sorted(policy_hashes)))

6.4 Encoding

Recommended canonical bytes:

  • deterministic CBOR (preferred)
  • or strict JSON canonicalization (RFC 8785-like rules) with explicit numeric rules

7. Obligations, Constraints, Evidence Blocks

7.1 Obligations

Obligations are mandatory requirements enforced post-issuance:

  • require_anchor: true
  • require_two_person_rule: true
  • require_evidence_fields: ["tx_hash","bytecode_hash", ...]
  • require_approvals: { group: "security", count: 2 }
  • require_attestation: { type: "sbom", verified: true }
  • require_emergency_lockout: { duration_seconds: 3600 }

If obligations cannot be satisfied → evidence submission fails → enforcement actions.

7.2 Constraints

Constraints bound the grant:

  • allowed_chains: ["ethereum:1","arbitrum:42161"]
  • max_ttl_seconds: 90
  • allowed_branches: ["main"]
  • allowed_artifacts: { digest_alg: "sha256", source: "registry" }

Constraints are validated during grant issuance and during evidence validation.

7.3 Evidence block

Defines anchoring behavior and commitments:

  • anchor_epoch_seconds: 60
  • merkle_domain: "QTRUST:EVIDENCE"

8. Standard Policy Library (Short Set)

8.1 Deny upgrades outside approved window

policy deny_upgrades_outside_window {
  meta { id: "POL-DENY-UPGRADE-OUTSIDE-WINDOW"; owner: "security"; version: "1.0.0"; }

  match { action: "web3.contract.upgrade"; resource: { type: "proxy", chain: "evm", network: glob("*") }; }

  effect: deny;
  when: not within_time_window(context.time.utc, "12:00", "23:00", "UTC");
}

8.2 Mainnet deploy requires signed release + SLSA + SBOM + 2 approvals

policy deploy_evm_mainnet_release {
  meta { id: "POL-DEPLOY-EVM-MAINNET-RELEASE"; owner: "platform-security"; version: "1.0.0"; severity: "critical"; }

  match { action: "web3.contract.deploy"; resource: { type: "contract", chain: "evm", network: glob("mainnet*") }; }

  effect: allow;
  when: (
    context.git.branch == "main" and
    context.git.tag matches regex("^v[0-9]+\\.[0-9]+\\.[0-9]+$") and
    attestations.slsa.present == true and
    attestations.sbom.present == true and
    attestations.commit.signature_valid == true and
    attestations.approvals.group == "security" and
    attestations.approvals.count >= 2
  );

  obligations {
    require_anchor: true;
    require_two_person_rule: true;
    require_evidence_fields: ["tx_hash","contract_address","bytecode_hash","artifact_digest","pipeline_run_url"];
  }

  ttl: 90s;
}

8.3 Terraform apply in prod requires signed plan + evidence

policy terraform_apply_prod_strict {
  meta { id: "POL-IAC-PROD-APPLY-STRICT"; owner: "devsecops"; version: "1.2.0"; severity: "high"; }

  match { action: "iac.terraform.apply"; resource: { type: "terraform", env: "prod" }; }

  effect: allow;
  when: (
    context.git.branch == "main" and
    attestations.terraform.plan_signed == true and
    attestations.slsa.present == true and
    attestations.sbom.present == true and
    is_defined(context.change_ticket) == true
  );

  obligations {
    require_anchor: true;
    require_evidence_fields: ["plan_digest","apply_log_digest","pipeline_run_url","change_ticket"];
  }

  ttl: 120s;
}

9. Implementation Checklist (Reference)

To implement QPL correctly:

  • lexer & parser → AST
  • type checks for operators and functions
  • undefined semantics exactly as specified
  • deterministic set ordering & canonicalization rules
  • domain-separated hashing
  • deny-wins resolution
  • stable resource selector matching (glob/regex)
  • unit tests with golden canonical bytes (cross-language)
  • fuzz tests for parser (security)
  • policy bundle signing + verification (hybrid)

10. Notes on Versioning

  • QPL policies must include:

    • meta.id
    • meta.version (semver)
  • Policy bundle signature binds:

    • the canonical policy set
    • the policy set hash
  • Any runtime policy change is detectable via policy hash differences.


QPL is the governance core of Q-Trust: deterministic authorization that can be hashed, signed, and proven.