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.deployweb3.contract.upgradeweb3.bridge.rotate_signersiac.terraform.applyk8s.admission.create_podsecrets.lease.readml.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.shacontext.pipeline.run_id,context.pipeline.job_id,context.pipeline.urlcontext.artifact.digest(sha256/...)context.change_ticket(enterprise)
1.5 attestations
Verified proofs and metadata:
attestations.slsa.present,attestations.slsa.digest,attestations.slsa.verifiedattestations.sbom.present,attestations.sbom.digest,attestations.sbom.verifiedattestations.commit.signature_validattestations.approvals.group,attestations.approvals.countattestations.terraform.plan_signedattestations.model.provenance.present
2. Type System
2.1 Primitive types
boolint(signed 64-bit)string(UTF-8)bytes(opaque; base64 in API JSON)time(RFC3339 UTC instant)duration(seconds; source form may include30s,5m,2h)semver(semantic version)cidrhash(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
undefinedevaluate tofalse
(except explicit checks viais_defined(x))
3. Operators and Built-ins
3.1 Comparison operators
==,!=(same-type only)<,<=,>,>=forint,time,duration,semverinmembership:"main" in {"main","release"}subject.issuer in {"issuerA","issuerB"}
matchesregex 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) -> boolends_with(str, suffix) -> boolcontains(str, needle) -> bool
3.4 Time helpers (functions)
within_time_window(time, "HH:MM", "HH:MM", "TZ") -> booltime_between(t, start_time, end_time) -> bool(optional alias)
3.5 Hash helpers
hash(alg, hex_or_b64) -> hashhash_eq(a, b) -> bool(checks alg match + value match)hash_alg(h) -> string
3.6 Defined checks
is_defined(x) -> boolcoalesce(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.actionmatch.resourcematches 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 undefined→false;true and undefined→falsedue to undefined comparisons)
5.3 Resolution (deny-wins)
Deterministic resolution:
- Evaluate all candidate policies with
when == true. - If any policy has
effect: deny, DENY. - Else if any policy has
effect: allow, ALLOW. - 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: truerequire_two_person_rule: truerequire_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: 90allowed_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: 60merkle_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.idmeta.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.