//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `governance/capability/enable`. Version: `0.1`.
#[allow(unused_imports)]
use serde::{Deserialize, Serialize};
/// Error types.
pub mod error {
/// Error from a `TryFrom` or `FromStr` implementation.
pub struct ConversionError(::std::borrow::Cow<'static, str>);
impl ::std::error::Error for ConversionError {}
impl ::std::fmt::Display for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Display::fmt(&self.0, f)
}
}
impl ::std::fmt::Debug for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Debug::fmt(&self.0, f)
}
}
impl From<&'static str> for ConversionError {
fn from(value: &'static str) -> Self {
Self(value.into())
}
}
impl From<String> for ConversionError {
fn from(value: String) -> Self {
Self(value.into())
}
}
}
///The self-description of a pluggable community capability: the Trust Task families it serves, the trust-registry vocabulary it reads and writes, the roles that may operate it, the membership lifecycle hooks it consumes, and the external adapters that act on its decisions. The manifest is what governance approves, what discovery advertises, and what a management UX renders.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "CapabilityManifest",
/// "description": "The self-description of a pluggable community capability: the Trust Task families it serves, the trust-registry vocabulary it reads and writes, the roles that may operate it, the membership lifecycle hooks it consumes, and the external adapters that act on its decisions. The manifest is what governance approves, what discovery advertises, and what a management UX renders.",
/// "type": "object",
/// "required": [
/// "capability",
/// "specs",
/// "version"
/// ],
/// "properties": {
/// "capability": {
/// "description": "The capability's namespace slug, e.g. `git-trust`.",
/// "type": "string",
/// "pattern": "^[a-z0-9][a-z0-9-]*$"
/// },
/// "configSchema": {
/// "description": "Spec slug of the JSON schema the per-community `config` document must validate against.",
/// "type": "string"
/// },
/// "consentClass": {
/// "description": "Map of capability operation to the consent class its execution requires under the host's delegated-execution policy.",
/// "type": "object",
/// "additionalProperties": {
/// "type": "string",
/// "enum": [
/// "normal",
/// "elevated",
/// "destructive"
/// ]
/// }
/// },
/// "description": {
/// "description": "One-paragraph description for management surfaces.",
/// "type": "string"
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "externalAdapters": {
/// "description": "Out-of-stack components that consume this capability's trust decisions.",
/// "type": "array",
/// "items": {
/// "type": "object",
/// "required": [
/// "kind",
/// "ref"
/// ],
/// "properties": {
/// "kind": {
/// "description": "Adapter type, e.g. `github-action`, `webhook`.",
/// "type": "string"
/// },
/// "ref": {
/// "description": "Where the adapter lives, e.g. a repository path or URL.",
/// "type": "string"
/// }
/// },
/// "additionalProperties": false
/// }
/// },
/// "lifecycleHooks": {
/// "description": "Membership lifecycle events the capability consumes, e.g. `member.enrolled`, `member.revoked`, `role.changed`.",
/// "type": "array",
/// "items": {
/// "type": "string"
/// }
/// },
/// "roles": {
/// "description": "Map of capability operation (e.g. `grant`, `view`) to the community roles allowed to perform it.",
/// "type": "object",
/// "additionalProperties": {
/// "type": "array",
/// "items": {
/// "type": "string"
/// }
/// }
/// },
/// "specs": {
/// "description": "Trust Task spec slugs (or `<family>/*` globs) this capability serves when enabled.",
/// "type": "array",
/// "items": {
/// "type": "string"
/// },
/// "minItems": 1
/// },
/// "title": {
/// "description": "Human-readable capability name for management surfaces.",
/// "type": "string"
/// },
/// "version": {
/// "description": "Manifest/capability version, `MAJOR.MINOR`.",
/// "type": "string",
/// "pattern": "^[0-9]+\\.[0-9]+$"
/// },
/// "vocabulary": {
/// "description": "The trust-registry tuple vocabulary this capability may read and write. A conforming host MUST reject writes by this capability whose `action` is not listed.",
/// "type": "object",
/// "required": [
/// "actions"
/// ],
/// "properties": {
/// "actions": {
/// "description": "TRQP `action` values this capability owns, e.g. `git.commit.sign`.",
/// "type": "array",
/// "items": {
/// "type": "string"
/// },
/// "minItems": 1
/// },
/// "resourcePattern": {
/// "description": "Human-readable pattern of the `resource` values used, e.g. `<org>[/<repo>]`.",
/// "type": "string"
/// }
/// },
/// "additionalProperties": false
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct CapabilityManifest {
///The capability's namespace slug, e.g. `git-trust`.
pub capability: CapabilityManifestCapability,
///Spec slug of the JSON schema the per-community `config` document must validate against.
#[serde(
rename = "configSchema",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub config_schema: ::std::option::Option<::std::string::String>,
///Map of capability operation to the consent class its execution requires under the host's delegated-execution policy.
#[serde(
rename = "consentClass",
default,
skip_serializing_if = ":: std :: collections :: HashMap::is_empty"
)]
pub consent_class:
::std::collections::HashMap<::std::string::String, CapabilityManifestConsentClassValue>,
///One-paragraph description for management surfaces.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub description: ::std::option::Option<::std::string::String>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///Out-of-stack components that consume this capability's trust decisions.
#[serde(
rename = "externalAdapters",
default,
skip_serializing_if = "::std::vec::Vec::is_empty"
)]
pub external_adapters: ::std::vec::Vec<CapabilityManifestExternalAdaptersItem>,
///Membership lifecycle events the capability consumes, e.g. `member.enrolled`, `member.revoked`, `role.changed`.
#[serde(
rename = "lifecycleHooks",
default,
skip_serializing_if = "::std::vec::Vec::is_empty"
)]
pub lifecycle_hooks: ::std::vec::Vec<::std::string::String>,
///Map of capability operation (e.g. `grant`, `view`) to the community roles allowed to perform it.
#[serde(
default,
skip_serializing_if = ":: std :: collections :: HashMap::is_empty"
)]
pub roles:
::std::collections::HashMap<::std::string::String, ::std::vec::Vec<::std::string::String>>,
///Trust Task spec slugs (or `<family>/*` globs) this capability serves when enabled.
pub specs: ::std::vec::Vec<::std::string::String>,
///Human-readable capability name for management surfaces.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub title: ::std::option::Option<::std::string::String>,
///Manifest/capability version, `MAJOR.MINOR`.
pub version: CapabilityManifestVersion,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub vocabulary: ::std::option::Option<CapabilityManifestVocabulary>,
}
///The capability's namespace slug, e.g. `git-trust`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The capability's namespace slug, e.g. `git-trust`.",
/// "type": "string",
/// "pattern": "^[a-z0-9][a-z0-9-]*$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct CapabilityManifestCapability(::std::string::String);
impl ::std::ops::Deref for CapabilityManifestCapability {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<CapabilityManifestCapability> for ::std::string::String {
fn from(value: CapabilityManifestCapability) -> Self {
value.0
}
}
impl ::std::str::FromStr for CapabilityManifestCapability {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^[a-z0-9][a-z0-9-]*$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z0-9][a-z0-9-]*$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for CapabilityManifestCapability {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for CapabilityManifestCapability {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for CapabilityManifestCapability {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for CapabilityManifestCapability {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`CapabilityManifestConsentClassValue`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "enum": [
/// "normal",
/// "elevated",
/// "destructive"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
pub enum CapabilityManifestConsentClassValue {
#[serde(rename = "normal")]
Normal,
#[serde(rename = "elevated")]
Elevated,
#[serde(rename = "destructive")]
Destructive,
}
impl ::std::fmt::Display for CapabilityManifestConsentClassValue {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Normal => f.write_str("normal"),
Self::Elevated => f.write_str("elevated"),
Self::Destructive => f.write_str("destructive"),
}
}
}
impl ::std::str::FromStr for CapabilityManifestConsentClassValue {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"normal" => Ok(Self::Normal),
"elevated" => Ok(Self::Elevated),
"destructive" => Ok(Self::Destructive),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for CapabilityManifestConsentClassValue {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for CapabilityManifestConsentClassValue {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for CapabilityManifestConsentClassValue {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`CapabilityManifestExternalAdaptersItem`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "object",
/// "required": [
/// "kind",
/// "ref"
/// ],
/// "properties": {
/// "kind": {
/// "description": "Adapter type, e.g. `github-action`, `webhook`.",
/// "type": "string"
/// },
/// "ref": {
/// "description": "Where the adapter lives, e.g. a repository path or URL.",
/// "type": "string"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct CapabilityManifestExternalAdaptersItem {
///Adapter type, e.g. `github-action`, `webhook`.
pub kind: ::std::string::String,
///Where the adapter lives, e.g. a repository path or URL.
#[serde(rename = "ref")]
pub ref_: ::std::string::String,
}
///Manifest/capability version, `MAJOR.MINOR`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Manifest/capability version, `MAJOR.MINOR`.",
/// "type": "string",
/// "pattern": "^[0-9]+\\.[0-9]+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct CapabilityManifestVersion(::std::string::String);
impl ::std::ops::Deref for CapabilityManifestVersion {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<CapabilityManifestVersion> for ::std::string::String {
fn from(value: CapabilityManifestVersion) -> Self {
value.0
}
}
impl ::std::str::FromStr for CapabilityManifestVersion {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^[0-9]+\\.[0-9]+$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[0-9]+\\.[0-9]+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for CapabilityManifestVersion {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for CapabilityManifestVersion {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for CapabilityManifestVersion {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for CapabilityManifestVersion {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///The trust-registry tuple vocabulary this capability may read and write. A conforming host MUST reject writes by this capability whose `action` is not listed.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The trust-registry tuple vocabulary this capability may read and write. A conforming host MUST reject writes by this capability whose `action` is not listed.",
/// "type": "object",
/// "required": [
/// "actions"
/// ],
/// "properties": {
/// "actions": {
/// "description": "TRQP `action` values this capability owns, e.g. `git.commit.sign`.",
/// "type": "array",
/// "items": {
/// "type": "string"
/// },
/// "minItems": 1
/// },
/// "resourcePattern": {
/// "description": "Human-readable pattern of the `resource` values used, e.g. `<org>[/<repo>]`.",
/// "type": "string"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct CapabilityManifestVocabulary {
///TRQP `action` values this capability owns, e.g. `git.commit.sign`.
pub actions: ::std::vec::Vec<::std::string::String>,
///Human-readable pattern of the `resource` values used, e.g. `<org>[/<repo>]`.
#[serde(
rename = "resourcePattern",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub resource_pattern: ::std::option::Option<::std::string::String>,
}
///Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Ext",
/// "description": "Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.",
/// "type": "object",
/// "minProperties": 1,
/// "additionalProperties": true,
/// "propertyNames": {
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(transparent)]
pub struct Ext(pub ::std::collections::HashMap<ExtKey, ::serde_json::Value>);
impl ::std::ops::Deref for Ext {
type Target = ::std::collections::HashMap<ExtKey, ::serde_json::Value>;
fn deref(&self) -> &::std::collections::HashMap<ExtKey, ::serde_json::Value> {
&self.0
}
}
impl ::std::convert::From<Ext> for ::std::collections::HashMap<ExtKey, ::serde_json::Value> {
fn from(value: Ext) -> Self {
value.0
}
}
impl ::std::convert::From<::std::collections::HashMap<ExtKey, ::serde_json::Value>> for Ext {
fn from(value: ::std::collections::HashMap<ExtKey, ::serde_json::Value>) -> Self {
Self(value)
}
}
///`ExtKey`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "type": "string",
/// "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ExtKey(::std::string::String);
impl ::std::ops::Deref for ExtKey {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ExtKey> for ::std::string::String {
fn from(value: ExtKey) -> Self {
value.0
}
}
impl ::std::str::FromStr for ExtKey {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new("^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$").unwrap()
});
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z][a-z0-9-]*(\\.[a-z0-9-]+)+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for ExtKey {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for ExtKey {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///A community operator enables a pluggable capability for a community. Activation registers the capability's Trust Task handlers, advertises it in discovery, and starts its lifecycle hooks; a community with no enable record carries none of the capability's records, surfaces, or attack surface.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://trusttasks.org/spec/governance/capability/enable/0.1",
/// "title": "Payload",
/// "description": "A community operator enables a pluggable capability for a community. Activation registers the capability's Trust Task handlers, advertises it in discovery, and starts its lifecycle hooks; a community with no enable record carries none of the capability's records, surfaces, or attack surface.",
/// "type": "object",
/// "required": [
/// "capability",
/// "version"
/// ],
/// "properties": {
/// "capability": {
/// "description": "Namespace slug of the capability to enable, e.g. `git-trust`.",
/// "type": "string",
/// "pattern": "^[a-z0-9][a-z0-9-]*$"
/// },
/// "config": {
/// "description": "Per-community configuration. Opaque to the framework; the recipient MUST validate it against the schema named by the capability manifest's `configSchema` and reject `config_invalid` on mismatch.",
/// "type": "object"
/// },
/// "delegate": {
/// "description": "DID of the companion service that serves this capability, for capabilities not built into the host. When present, the host records a namespace delegation to this DID and `manifest` is REQUIRED (the host cannot know a companion's manifest a priori).",
/// "type": "string"
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "manifest": {
/// "description": "The capability's manifest. OPTIONAL for built-in capabilities (the host knows it); REQUIRED when `delegate` is present.",
/// "$ref": "#/definitions/CapabilityManifest"
/// },
/// "version": {
/// "description": "Capability version to enable.",
/// "type": "string",
/// "pattern": "^[0-9]+\\.[0-9]+$"
/// }
/// },
/// "additionalProperties": false,
/// "dependentRequired": {
/// "delegate": [
/// "manifest"
/// ]
/// }
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct Payload {
///Namespace slug of the capability to enable, e.g. `git-trust`.
pub capability: PayloadCapability,
///Per-community configuration. Opaque to the framework; the recipient MUST validate it against the schema named by the capability manifest's `configSchema` and reject `config_invalid` on mismatch.
#[serde(default, skip_serializing_if = "::serde_json::Map::is_empty")]
pub config: ::serde_json::Map<::std::string::String, ::serde_json::Value>,
///DID of the companion service that serves this capability, for capabilities not built into the host. When present, the host records a namespace delegation to this DID and `manifest` is REQUIRED (the host cannot know a companion's manifest a priori).
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub delegate: ::std::option::Option<::std::string::String>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///The capability's manifest. OPTIONAL for built-in capabilities (the host knows it); REQUIRED when `delegate` is present.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub manifest: ::std::option::Option<CapabilityManifest>,
///Capability version to enable.
pub version: PayloadVersion,
}
///Namespace slug of the capability to enable, e.g. `git-trust`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Namespace slug of the capability to enable, e.g. `git-trust`.",
/// "type": "string",
/// "pattern": "^[a-z0-9][a-z0-9-]*$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadCapability(::std::string::String);
impl ::std::ops::Deref for PayloadCapability {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadCapability> for ::std::string::String {
fn from(value: PayloadCapability) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadCapability {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^[a-z0-9][a-z0-9-]*$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z0-9][a-z0-9-]*$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadCapability {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadCapability {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadCapability {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadCapability {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///Capability version to enable.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Capability version to enable.",
/// "type": "string",
/// "pattern": "^[0-9]+\\.[0-9]+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct PayloadVersion(::std::string::String);
impl ::std::ops::Deref for PayloadVersion {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<PayloadVersion> for ::std::string::String {
fn from(value: PayloadVersion) -> Self {
value.0
}
}
impl ::std::str::FromStr for PayloadVersion {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^[0-9]+\\.[0-9]+$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[0-9]+\\.[0-9]+$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for PayloadVersion {
type Error = self::error::ConversionError;
fn try_from(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<&::std::string::String> for PayloadVersion {
type Error = self::error::ConversionError;
fn try_from(
value: &::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl ::std::convert::TryFrom<::std::string::String> for PayloadVersion {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
impl<'de> ::serde::Deserialize<'de> for PayloadVersion {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
::std::string::String::deserialize(deserializer)?
.parse()
.map_err(|e: self::error::ConversionError| {
<D::Error as ::serde::de::Error>::custom(e.to_string())
})
}
}
///`Response`
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Response",
/// "type": "object",
/// "required": [
/// "capability",
/// "enabled"
/// ],
/// "properties": {
/// "capability": {
/// "type": "string"
/// },
/// "enabled": {
/// "description": "True once the capability is active for the community.",
/// "type": "boolean"
/// },
/// "enabledAt": {
/// "description": "When the enablement took effect, per the host clock.",
/// "type": "string",
/// "format": "date-time"
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "message": {
/// "description": "Additional human-readable detail.",
/// "type": "string"
/// },
/// "version": {
/// "type": "string"
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "response"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct Response {
pub capability: ::std::string::String,
///True once the capability is active for the community.
pub enabled: bool,
///When the enablement took effect, per the host clock.
#[serde(
rename = "enabledAt",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub enabled_at: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///Additional human-readable detail.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub message: ::std::option::Option<::std::string::String>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub version: ::std::option::Option<::std::string::String>,
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/governance/capability/enable/0.1";
const IS_PROOF_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
}
impl crate::Payload for Response {
const TYPE_URI: &'static str =
"https://trusttasks.org/spec/governance/capability/enable/0.1#response";
const IS_PROOF_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
}
#[cfg(feature = "validate")]
impl crate::validate::ValidatedPayload for Payload {
const SCHEMA_JSON: &'static str = "{\n \"$defs\": {\n \"CapabilityManifest\": {\n \"additionalProperties\": false,\n \"description\": \"The self-description of a pluggable community capability: the Trust Task families it serves, the trust-registry vocabulary it reads and writes, the roles that may operate it, the membership lifecycle hooks it consumes, and the external adapters that act on its decisions. The manifest is what governance approves, what discovery advertises, and what a management UX renders.\",\n \"properties\": {\n \"capability\": {\n \"description\": \"The capability's namespace slug, e.g. `git-trust`.\",\n \"pattern\": \"^[a-z0-9][a-z0-9-]*$\",\n \"type\": \"string\"\n },\n \"configSchema\": {\n \"description\": \"Spec slug of the JSON schema the per-community `config` document must validate against.\",\n \"type\": \"string\"\n },\n \"consentClass\": {\n \"additionalProperties\": {\n \"enum\": [\n \"normal\",\n \"elevated\",\n \"destructive\"\n ],\n \"type\": \"string\"\n },\n \"description\": \"Map of capability operation to the consent class its execution requires under the host's delegated-execution policy.\",\n \"type\": \"object\"\n },\n \"description\": {\n \"description\": \"One-paragraph description for management surfaces.\",\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"externalAdapters\": {\n \"description\": \"Out-of-stack components that consume this capability's trust decisions.\",\n \"items\": {\n \"additionalProperties\": false,\n \"properties\": {\n \"kind\": {\n \"description\": \"Adapter type, e.g. `github-action`, `webhook`.\",\n \"type\": \"string\"\n },\n \"ref\": {\n \"description\": \"Where the adapter lives, e.g. a repository path or URL.\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"kind\",\n \"ref\"\n ],\n \"type\": \"object\"\n },\n \"type\": \"array\"\n },\n \"lifecycleHooks\": {\n \"description\": \"Membership lifecycle events the capability consumes, e.g. `member.enrolled`, `member.revoked`, `role.changed`.\",\n \"items\": {\n \"type\": \"string\"\n },\n \"type\": \"array\"\n },\n \"roles\": {\n \"additionalProperties\": {\n \"items\": {\n \"type\": \"string\"\n },\n \"type\": \"array\"\n },\n \"description\": \"Map of capability operation (e.g. `grant`, `view`) to the community roles allowed to perform it.\",\n \"type\": \"object\"\n },\n \"specs\": {\n \"description\": \"Trust Task spec slugs (or `<family>/*` globs) this capability serves when enabled.\",\n \"items\": {\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"type\": \"array\"\n },\n \"title\": {\n \"description\": \"Human-readable capability name for management surfaces.\",\n \"type\": \"string\"\n },\n \"version\": {\n \"description\": \"Manifest/capability version, `MAJOR.MINOR`.\",\n \"pattern\": \"^[0-9]+\\\\.[0-9]+$\",\n \"type\": \"string\"\n },\n \"vocabulary\": {\n \"additionalProperties\": false,\n \"description\": \"The trust-registry tuple vocabulary this capability may read and write. A conforming host MUST reject writes by this capability whose `action` is not listed.\",\n \"properties\": {\n \"actions\": {\n \"description\": \"TRQP `action` values this capability owns, e.g. `git.commit.sign`.\",\n \"items\": {\n \"type\": \"string\"\n },\n \"minItems\": 1,\n \"type\": \"array\"\n },\n \"resourcePattern\": {\n \"description\": \"Human-readable pattern of the `resource` values used, e.g. `<org>[/<repo>]`.\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"actions\"\n ],\n \"type\": \"object\"\n }\n },\n \"required\": [\n \"capability\",\n \"version\",\n \"specs\"\n ],\n \"title\": \"CapabilityManifest\",\n \"type\": \"object\"\n },\n \"Ext\": {\n \"additionalProperties\": true,\n \"description\": \"Vendor-namespaced extension object per SPEC.md §4.5.1. Each immediate key MUST be a reverse-DNS namespace; structure under each namespace is opaque to the framework.\",\n \"minProperties\": 1,\n \"propertyNames\": {\n \"pattern\": \"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"\n },\n \"title\": \"Ext\",\n \"type\": \"object\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"properties\": {\n \"capability\": {\n \"type\": \"string\"\n },\n \"enabled\": {\n \"description\": \"True once the capability is active for the community.\",\n \"type\": \"boolean\"\n },\n \"enabledAt\": {\n \"description\": \"When the enablement took effect, per the host clock.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"message\": {\n \"description\": \"Additional human-readable detail.\",\n \"type\": \"string\"\n },\n \"version\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"capability\",\n \"enabled\"\n ],\n \"title\": \"Governance Capability Enable — response payload\",\n \"type\": \"object\"\n }\n },\n \"$id\": \"https://trusttasks.org/spec/governance/capability/enable/0.1\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"additionalProperties\": false,\n \"dependentRequired\": {\n \"delegate\": [\n \"manifest\"\n ]\n },\n \"description\": \"A community operator enables a pluggable capability for a community. Activation registers the capability's Trust Task handlers, advertises it in discovery, and starts its lifecycle hooks; a community with no enable record carries none of the capability's records, surfaces, or attack surface.\",\n \"properties\": {\n \"capability\": {\n \"description\": \"Namespace slug of the capability to enable, e.g. `git-trust`.\",\n \"pattern\": \"^[a-z0-9][a-z0-9-]*$\",\n \"type\": \"string\"\n },\n \"config\": {\n \"description\": \"Per-community configuration. Opaque to the framework; the recipient MUST validate it against the schema named by the capability manifest's `configSchema` and reject `config_invalid` on mismatch.\",\n \"type\": \"object\"\n },\n \"delegate\": {\n \"description\": \"DID of the companion service that serves this capability, for capabilities not built into the host. When present, the host records a namespace delegation to this DID and `manifest` is REQUIRED (the host cannot know a companion's manifest a priori).\",\n \"type\": \"string\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"manifest\": {\n \"$ref\": \"#/$defs/CapabilityManifest\",\n \"description\": \"The capability's manifest. OPTIONAL for built-in capabilities (the host knows it); REQUIRED when `delegate` is present.\"\n },\n \"version\": {\n \"description\": \"Capability version to enable.\",\n \"pattern\": \"^[0-9]+\\\\.[0-9]+$\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"capability\",\n \"version\"\n ],\n \"title\": \"Governance Capability Enable — payload\",\n \"type\": \"object\"\n}\n";
}
#[cfg(test)]
mod conformance {
//! Round-trip tests harvested from the spec's `spec.md`,
//! plus a `rejects_invalid_examples` test for any fixtures
//! in `payload.invalid-examples.json` (validate feature).
/// Each fixture in `payload.invalid-examples.json` MUST be
/// rejected by at least one of: serde deserialization, or
/// JSON-Schema validation under the `validate` feature. The
/// fixture file documents the producer-side bug class that
/// each payload exemplifies; this generated test pins it.
#[cfg(feature = "validate")]
#[test]
fn rejects_invalid_examples() {
use crate::validate::ValidatedPayload;
let fixtures: &[(&str, &str)] = &[
("Empty payload omits the required members capability and version.", "{}"),
(
"Unknown top-level member is rejected (additionalProperties: false).",
"{\n \"__notARealMember__\": true,\n \"capability\": \"git-trust\",\n \"version\": \"0.1\"\n}",
),
(
"capability must match the slug pattern (no uppercase).",
"{\n \"capability\": \"GitTrust\",\n \"version\": \"0.1\"\n}",
),
(
"version must be MAJOR.MINOR.",
"{\n \"capability\": \"git-trust\",\n \"version\": \"one\"\n}",
),
(
"delegate without manifest is rejected (dependentRequired).",
"{\n \"capability\": \"git-trust\",\n \"delegate\": \"did:example:companion\",\n \"version\": \"0.1\"\n}",
),
(
"config must be an object, not a string.",
"{\n \"capability\": \"git-trust\",\n \"config\": \"grantOnRole=maintainer\",\n \"version\": \"0.1\"\n}",
),
];
for (i, (note, raw)) in fixtures.iter().enumerate() {
let value: serde_json::Value = match serde_json::from_str(raw) {
Ok(v) => v,
Err(_) => continue,
};
let serde_ok = serde_json::from_value::<super::Payload>(value.clone()).is_ok();
let schema_ok = super::Payload::validate_value(&value).is_ok();
assert!(
!(serde_ok && schema_ok),
"invalid-example #{} ({:?}) was accepted by both serde and JSON Schema; \
the fixture's stated failure class is no longer caught:\n{}",
i + 1,
note,
raw
);
}
}
}