//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `git-ns/view`. Version: `0.5`.
#[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())
}
}
}
///Whether each step that turns commit trust on for a repository is in place, as last reported. A step that this forge's plan does not need reads `true`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Bootstrap",
/// "description": "Whether each step that turns commit trust on for a repository is in place, as last reported. A step that this forge's plan does not need reads `true`.",
/// "type": "object",
/// "required": [
/// "keyring",
/// "requiredCheck",
/// "variables",
/// "workflow"
/// ],
/// "properties": {
/// "keyring": {
/// "description": "The exempt platform keyring for forge-signed merge commits is committed, or the forge's plan does not need one.",
/// "type": "boolean"
/// },
/// "requiredCheck": {
/// "description": "The forge refuses to merge into the default branch unless the verify-trust check passes, with no bypass, and a pull request cannot change what that check runs: an organisation-required workflow, code-owner review of workflow files, or protected workflow paths, as the forge allows.",
/// "type": "boolean"
/// },
/// "variables": {
/// "description": "The repository names the Trust Registry and this VTC as its trust anchors.",
/// "type": "boolean"
/// },
/// "workflow": {
/// "description": "The verify-trust check runs on the repository's pull requests — from a workflow committed to it, or, where the forge supports it, required on it from the namespace's own bridge-managed workflow repository at a pinned commit.",
/// "type": "boolean"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Bootstrap {
///The exempt platform keyring for forge-signed merge commits is committed, or the forge's plan does not need one.
pub keyring: bool,
///The forge refuses to merge into the default branch unless the verify-trust check passes, with no bypass, and a pull request cannot change what that check runs: an organisation-required workflow, code-owner review of workflow files, or protected workflow paths, as the forge allows.
#[serde(rename = "requiredCheck")]
pub required_check: bool,
///The repository names the Trust Registry and this VTC as its trust anchors.
pub variables: bool,
///The verify-trust check runs on the repository's pull requests — from a workflow committed to it, or, where the forge supports it, required on it from the namespace's own bridge-managed workflow repository at a pinned commit.
pub workflow: bool,
}
impl Bootstrap {
pub fn builder() -> builder::Bootstrap {
Default::default()
}
}
///How a self-granted right came to be, and whether another administrator has since ratified it. A record whose `breakGlass` has no `ratifiedBy` is **unratified**: it is live and published like any other right, it does not count toward the last-owner or last-admin invariants, and any community administrator or namespace admin of its namespace may revoke it. Ratification (git-ns/right/ratify) sets `ratifiedBy` and `ratifiedAt`; from then on the record is an ordinary grant, and `breakGlass` stays as its history. Never published to the Trust Registry.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "BreakGlass",
/// "description": "How a self-granted right came to be, and whether another administrator has since ratified it. A record whose `breakGlass` has no `ratifiedBy` is **unratified**: it is live and published like any other right, it does not count toward the last-owner or last-admin invariants, and any community administrator or namespace admin of its namespace may revoke it. Ratification (git-ns/right/ratify) sets `ratifiedBy` and `ratifiedAt`; from then on the record is an ordinary grant, and `breakGlass` stays as its history. Never published to the Trust Registry.",
/// "type": "object",
/// "required": [
/// "at",
/// "by",
/// "justification"
/// ],
/// "properties": {
/// "at": {
/// "description": "When the VTC recorded the break-glass.",
/// "type": "string",
/// "format": "date-time"
/// },
/// "by": {
/// "description": "Who broke the glass: always the record's `subject`, restated so the flag reads on its own.",
/// "$ref": "#/definitions/Did"
/// },
/// "effectiveAt": {
/// "description": "When the right takes effect, where the community's policy imposed a delay. Absent: it took effect at `at`. Until this instant the record confers nothing and is not published, and any administrator who may revoke it may do so.",
/// "type": "string",
/// "format": "date-time"
/// },
/// "justification": {
/// "description": "The actor's statement of why nobody else could grant this right. Shown to every community administrator, every namespace admin of the namespace and every owner of the resource; kept in the audit record; never published.",
/// "type": "string",
/// "maxLength": 2048,
/// "minLength": 1,
/// "pattern": "\\S"
/// },
/// "ratifiedAt": {
/// "description": "When it was ratified. Present exactly when `ratifiedBy` is.",
/// "type": "string",
/// "format": "date-time"
/// },
/// "ratifiedBy": {
/// "description": "The administrator who ratified the record — never its subject. Absent while unratified.",
/// "$ref": "#/definitions/Did"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct BreakGlass {
///When the VTC recorded the break-glass.
pub at: ::chrono::DateTime<::chrono::offset::Utc>,
///Who broke the glass: always the record's `subject`, restated so the flag reads on its own.
pub by: Did,
///When the right takes effect, where the community's policy imposed a delay. Absent: it took effect at `at`. Until this instant the record confers nothing and is not published, and any administrator who may revoke it may do so.
#[serde(
rename = "effectiveAt",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub effective_at: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
///The actor's statement of why nobody else could grant this right. Shown to every community administrator, every namespace admin of the namespace and every owner of the resource; kept in the audit record; never published.
pub justification: BreakGlassJustification,
///When it was ratified. Present exactly when `ratifiedBy` is.
#[serde(
rename = "ratifiedAt",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub ratified_at: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
///The administrator who ratified the record — never its subject. Absent while unratified.
#[serde(
rename = "ratifiedBy",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub ratified_by: ::std::option::Option<Did>,
}
impl BreakGlass {
pub fn builder() -> builder::BreakGlass {
Default::default()
}
}
///The actor's statement of why nobody else could grant this right. Shown to every community administrator, every namespace admin of the namespace and every owner of the resource; kept in the audit record; never published.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The actor's statement of why nobody else could grant this right. Shown to every community administrator, every namespace admin of the namespace and every owner of the resource; kept in the audit record; never published.",
/// "type": "string",
/// "maxLength": 2048,
/// "minLength": 1,
/// "pattern": "\\S"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct BreakGlassJustification(::std::string::String);
impl ::std::ops::Deref for BreakGlassJustification {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<BreakGlassJustification> for ::std::string::String {
fn from(value: BreakGlassJustification) -> Self {
value.0
}
}
impl ::std::str::FromStr for BreakGlassJustification {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 2048usize {
return Err("longer than 2048 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("\\S").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"\\S\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for BreakGlassJustification {
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 BreakGlassJustification {
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 BreakGlassJustification {
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 BreakGlassJustification {
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 bare DID in the W3C DID Core syntax (§3.1): `did:`, a method name of lowercase letters and digits, `:`, and a method-specific id of colon-separated segments drawn from `A-Z a-z 0-9 . - _` and percent-encoded octets, the last segment non-empty. A DID URL is not a DID: no path, query or fragment (`/`, `?`, `#`), so a verification-method id such as `did:key:z6Mk…#z6Mk…` is refused. Compared by exact string equality — no case folding or percent-decoding. A consumer MUST still treat the value as data: the pattern keeps shell metacharacters, whitespace and quotes out of the wire form, but it does not make a DID safe to splice into a command or markup.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Did",
/// "description": "A bare DID in the W3C DID Core syntax (§3.1): `did:`, a method name of lowercase letters and digits, `:`, and a method-specific id of colon-separated segments drawn from `A-Z a-z 0-9 . - _` and percent-encoded octets, the last segment non-empty. A DID URL is not a DID: no path, query or fragment (`/`, `?`, `#`), so a verification-method id such as `did:key:z6Mk…#z6Mk…` is refused. Compared by exact string equality — no case folding or percent-decoding. A consumer MUST still treat the value as data: the pattern keeps shell metacharacters, whitespace and quotes out of the wire form, but it does not make a DID safe to splice into a command or markup.",
/// "type": "string",
/// "maxLength": 2048,
/// "pattern": "^did:[a-z0-9]+:(?:(?:[A-Za-z0-9._-]|%[0-9A-Fa-f]{2})*:)*(?:[A-Za-z0-9._-]|%[0-9A-Fa-f]{2})+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct Did(::std::string::String);
impl ::std::ops::Deref for Did {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<Did> for ::std::string::String {
fn from(value: Did) -> Self {
value.0
}
}
impl ::std::str::FromStr for Did {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 2048usize {
return Err("longer than 2048 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> = ::std::sync::LazyLock::new(
|| {
::regress::Regex::new(
"^did:[a-z0-9]+:(?:(?:[A-Za-z0-9._-]|%[0-9A-Fa-f]{2})*:)*(?:[A-Za-z0-9._-]|%[0-9A-Fa-f]{2})+$",
)
.unwrap()
},
);
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^did:[a-z0-9]+:(?:(?:[A-Za-z0-9._-]|%[0-9A-Fa-f]{2})*:)*(?:[A-Za-z0-9._-]|%[0-9A-Fa-f]{2})+$\""
.into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for Did {
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 Did {
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 Did {
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 Did {
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())
})
}
}
///One difference between the forge's observed state and the VTC's projection of a repository.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "DriftItem",
/// "description": "One difference between the forge's observed state and the VTC's projection of a repository.",
/// "type": "object",
/// "required": [
/// "resource",
/// "type"
/// ],
/// "properties": {
/// "account": {
/// "description": "Whose role differs, for the three role types.",
/// "$ref": "#/definitions/ForgeAccount"
/// },
/// "expected": {
/// "description": "What the projection calls for, in the forge's own vocabulary. Absent when the projection calls for nothing.",
/// "type": "string",
/// "maxLength": 256
/// },
/// "observed": {
/// "description": "What the forge shows, in the forge's own vocabulary (a role name such as `maintain`, a setting name). Absent when nothing is there.",
/// "type": "string",
/// "maxLength": 256
/// },
/// "resource": {
/// "$ref": "#/definitions/RepoResource"
/// },
/// "type": {
/// "description": "`roleAdded` — someone holds a forge role the projection does not give them. `roleRemoved` — a projected role is missing. `roleChanged` — a projected role is present at another level. `requiredCheckMissing` — the verify-trust check is no longer required. `protectionWeakened` — branch protection or a ruleset is weaker than the projection in another way (force-push allowed, bypass actors added). `bootstrapMissing` — a bootstrap file or variable is gone.",
/// "type": "string",
/// "enum": [
/// "roleAdded",
/// "roleRemoved",
/// "roleChanged",
/// "requiredCheckMissing",
/// "protectionWeakened",
/// "bootstrapMissing"
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct DriftItem {
///Whose role differs, for the three role types.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub account: ::std::option::Option<ForgeAccount>,
///What the projection calls for, in the forge's own vocabulary. Absent when the projection calls for nothing.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub expected: ::std::option::Option<DriftItemExpected>,
///What the forge shows, in the forge's own vocabulary (a role name such as `maintain`, a setting name). Absent when nothing is there.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub observed: ::std::option::Option<DriftItemObserved>,
pub resource: RepoResource,
///`roleAdded` — someone holds a forge role the projection does not give them. `roleRemoved` — a projected role is missing. `roleChanged` — a projected role is present at another level. `requiredCheckMissing` — the verify-trust check is no longer required. `protectionWeakened` — branch protection or a ruleset is weaker than the projection in another way (force-push allowed, bypass actors added). `bootstrapMissing` — a bootstrap file or variable is gone.
#[serde(rename = "type")]
pub type_: DriftItemType,
}
impl DriftItem {
pub fn builder() -> builder::DriftItem {
Default::default()
}
}
///What the projection calls for, in the forge's own vocabulary. Absent when the projection calls for nothing.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "What the projection calls for, in the forge's own vocabulary. Absent when the projection calls for nothing.",
/// "type": "string",
/// "maxLength": 256
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DriftItemExpected(::std::string::String);
impl ::std::ops::Deref for DriftItemExpected {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DriftItemExpected> for ::std::string::String {
fn from(value: DriftItemExpected) -> Self {
value.0
}
}
impl ::std::str::FromStr for DriftItemExpected {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 256usize {
return Err("longer than 256 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DriftItemExpected {
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 DriftItemExpected {
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 DriftItemExpected {
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 DriftItemExpected {
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())
})
}
}
///What the forge shows, in the forge's own vocabulary (a role name such as `maintain`, a setting name). Absent when nothing is there.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "What the forge shows, in the forge's own vocabulary (a role name such as `maintain`, a setting name). Absent when nothing is there.",
/// "type": "string",
/// "maxLength": 256
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct DriftItemObserved(::std::string::String);
impl ::std::ops::Deref for DriftItemObserved {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<DriftItemObserved> for ::std::string::String {
fn from(value: DriftItemObserved) -> Self {
value.0
}
}
impl ::std::str::FromStr for DriftItemObserved {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 256usize {
return Err("longer than 256 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for DriftItemObserved {
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 DriftItemObserved {
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 DriftItemObserved {
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 DriftItemObserved {
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())
})
}
}
///`roleAdded` — someone holds a forge role the projection does not give them. `roleRemoved` — a projected role is missing. `roleChanged` — a projected role is present at another level. `requiredCheckMissing` — the verify-trust check is no longer required. `protectionWeakened` — branch protection or a ruleset is weaker than the projection in another way (force-push allowed, bypass actors added). `bootstrapMissing` — a bootstrap file or variable is gone.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "`roleAdded` — someone holds a forge role the projection does not give them. `roleRemoved` — a projected role is missing. `roleChanged` — a projected role is present at another level. `requiredCheckMissing` — the verify-trust check is no longer required. `protectionWeakened` — branch protection or a ruleset is weaker than the projection in another way (force-push allowed, bypass actors added). `bootstrapMissing` — a bootstrap file or variable is gone.",
/// "type": "string",
/// "enum": [
/// "roleAdded",
/// "roleRemoved",
/// "roleChanged",
/// "requiredCheckMissing",
/// "protectionWeakened",
/// "bootstrapMissing"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum DriftItemType {
#[serde(rename = "roleAdded")]
RoleAdded,
#[serde(rename = "roleRemoved")]
RoleRemoved,
#[serde(rename = "roleChanged")]
RoleChanged,
#[serde(rename = "requiredCheckMissing")]
RequiredCheckMissing,
#[serde(rename = "protectionWeakened")]
ProtectionWeakened,
#[serde(rename = "bootstrapMissing")]
BootstrapMissing,
}
impl ::std::fmt::Display for DriftItemType {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::RoleAdded => f.write_str("roleAdded"),
Self::RoleRemoved => f.write_str("roleRemoved"),
Self::RoleChanged => f.write_str("roleChanged"),
Self::RequiredCheckMissing => f.write_str("requiredCheckMissing"),
Self::ProtectionWeakened => f.write_str("protectionWeakened"),
Self::BootstrapMissing => f.write_str("bootstrapMissing"),
}
}
}
impl ::std::str::FromStr for DriftItemType {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"roleAdded" => Ok(Self::RoleAdded),
"roleRemoved" => Ok(Self::RoleRemoved),
"roleChanged" => Ok(Self::RoleChanged),
"requiredCheckMissing" => Ok(Self::RequiredCheckMissing),
"protectionWeakened" => Ok(Self::ProtectionWeakened),
"bootstrapMissing" => Ok(Self::BootstrapMissing),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for DriftItemType {
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 DriftItemType {
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 DriftItemType {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///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 person's account on one forge. `id` is authoritative; `login` is for display only, because logins can be renamed and re-registered.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ForgeAccount",
/// "description": "A person's account on one forge. `id` is authoritative; `login` is for display only, because logins can be renamed and re-registered.",
/// "type": "object",
/// "required": [
/// "forge",
/// "id",
/// "login"
/// ],
/// "properties": {
/// "forge": {
/// "$ref": "#/definitions/ForgeHost"
/// },
/// "id": {
/// "$ref": "#/definitions/ForgeId"
/// },
/// "login": {
/// "description": "The account's current login, as the forge reported it when last seen. Display only.",
/// "type": "string",
/// "maxLength": 100,
/// "minLength": 1
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct ForgeAccount {
pub forge: ForgeHost,
pub id: ForgeId,
///The account's current login, as the forge reported it when last seen. Display only.
pub login: ForgeAccountLogin,
}
impl ForgeAccount {
pub fn builder() -> builder::ForgeAccount {
Default::default()
}
}
///The account's current login, as the forge reported it when last seen. Display only.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The account's current login, as the forge reported it when last seen. Display only.",
/// "type": "string",
/// "maxLength": 100,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ForgeAccountLogin(::std::string::String);
impl ::std::ops::Deref for ForgeAccountLogin {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ForgeAccountLogin> for ::std::string::String {
fn from(value: ForgeAccountLogin) -> Self {
value.0
}
}
impl ::std::str::FromStr for ForgeAccountLogin {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 100usize {
return Err("longer than 100 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ForgeAccountLogin {
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 ForgeAccountLogin {
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 ForgeAccountLogin {
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 ForgeAccountLogin {
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 lowercased DNS host of a forge: `github.com`, a GitHub Enterprise Server host, `codeberg.org`, or a self-hosted Forgejo instance such as `git.example.org`. No scheme, no port, no path. The host is a segment of every resource, so a right never crosses forges.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ForgeHost",
/// "description": "The lowercased DNS host of a forge: `github.com`, a GitHub Enterprise Server host, `codeberg.org`, or a self-hosted Forgejo instance such as `git.example.org`. No scheme, no port, no path. The host is a segment of every resource, so a right never crosses forges.",
/// "type": "string",
/// "maxLength": 253,
/// "minLength": 3,
/// "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ForgeHost(::std::string::String);
impl ::std::ops::Deref for ForgeHost {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ForgeHost> for ::std::string::String {
fn from(value: ForgeHost) -> Self {
value.0
}
}
impl ::std::str::FromStr for ForgeHost {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 253usize {
return Err("longer than 253 characters".into());
}
if value.chars().count() < 3usize {
return Err("shorter than 3 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| {
::regress::Regex::new(
"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[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-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$\""
.into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ForgeHost {
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 ForgeHost {
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 ForgeHost {
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 ForgeHost {
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())
})
}
}
///An identifier the forge itself assigns — a repository id, a user or organisation id — carried as a string so a forge whose ids are not numbers needs no new version. GitHub and Forgejo ids are decimal integers written as strings (`"812736451"`). Unlike a name, it survives renames and transfers, which is why rights and bindings are keyed by it.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "ForgeId",
/// "description": "An identifier the forge itself assigns — a repository id, a user or organisation id — carried as a string so a forge whose ids are not numbers needs no new version. GitHub and Forgejo ids are decimal integers written as strings (`\"812736451\"`). Unlike a name, it survives renames and transfers, which is why rights and bindings are keyed by it.",
/// "type": "string",
/// "maxLength": 64,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ForgeId(::std::string::String);
impl ::std::ops::Deref for ForgeId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ForgeId> for ::std::string::String {
fn from(value: ForgeId) -> Self {
value.0
}
}
impl ::std::str::FromStr for ForgeId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 64usize {
return Err("longer than 64 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for ForgeId {
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 ForgeId {
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 ForgeId {
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 ForgeId {
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 VTC's binding to one owner on one forge.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "GitNamespace",
/// "description": "The VTC's binding to one owner on one forge.",
/// "type": "object",
/// "required": [
/// "forge",
/// "id",
/// "mode",
/// "owner",
/// "state"
/// ],
/// "properties": {
/// "forge": {
/// "$ref": "#/definitions/ForgeHost"
/// },
/// "id": {
/// "$ref": "#/definitions/NamespaceId"
/// },
/// "kind": {
/// "description": "Whether the owner is an organisation or a personal account, as the forge reports it. Present once known: a bridge-mode namespace learns it when binding completes, and a manual-mode namespace MAY never learn it.",
/// "type": "string",
/// "enum": [
/// "organization",
/// "user"
/// ]
/// },
/// "mode": {
/// "description": "`bridge` — a bridge service acts on the forge for this namespace (creates repositories, projects roles, reports drift). `manual` — no automation; people with forge access carry out the steps the VTC names, and the VTC governs the rights alone.",
/// "type": "string",
/// "enum": [
/// "bridge",
/// "manual"
/// ]
/// },
/// "owner": {
/// "description": "The organisation or user on the forge, lowercased.",
/// "$ref": "#/definitions/Segment"
/// },
/// "state": {
/// "description": "`pending` — binding has started and the forge-side proof has not arrived yet. `bound` — the VTC governs rights under this namespace.",
/// "type": "string",
/// "enum": [
/// "pending",
/// "bound"
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct GitNamespace {
pub forge: ForgeHost,
pub id: NamespaceId,
///Whether the owner is an organisation or a personal account, as the forge reports it. Present once known: a bridge-mode namespace learns it when binding completes, and a manual-mode namespace MAY never learn it.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub kind: ::std::option::Option<GitNamespaceKind>,
///`bridge` — a bridge service acts on the forge for this namespace (creates repositories, projects roles, reports drift). `manual` — no automation; people with forge access carry out the steps the VTC names, and the VTC governs the rights alone.
pub mode: GitNamespaceMode,
///The organisation or user on the forge, lowercased.
pub owner: Segment,
///`pending` — binding has started and the forge-side proof has not arrived yet. `bound` — the VTC governs rights under this namespace.
pub state: GitNamespaceState,
}
impl GitNamespace {
pub fn builder() -> builder::GitNamespace {
Default::default()
}
}
///Whether the owner is an organisation or a personal account, as the forge reports it. Present once known: a bridge-mode namespace learns it when binding completes, and a manual-mode namespace MAY never learn it.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "Whether the owner is an organisation or a personal account, as the forge reports it. Present once known: a bridge-mode namespace learns it when binding completes, and a manual-mode namespace MAY never learn it.",
/// "type": "string",
/// "enum": [
/// "organization",
/// "user"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum GitNamespaceKind {
#[serde(rename = "organization")]
Organization,
#[serde(rename = "user")]
User,
}
impl ::std::fmt::Display for GitNamespaceKind {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Organization => f.write_str("organization"),
Self::User => f.write_str("user"),
}
}
}
impl ::std::str::FromStr for GitNamespaceKind {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"organization" => Ok(Self::Organization),
"user" => Ok(Self::User),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for GitNamespaceKind {
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 GitNamespaceKind {
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 GitNamespaceKind {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`bridge` — a bridge service acts on the forge for this namespace (creates repositories, projects roles, reports drift). `manual` — no automation; people with forge access carry out the steps the VTC names, and the VTC governs the rights alone.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "`bridge` — a bridge service acts on the forge for this namespace (creates repositories, projects roles, reports drift). `manual` — no automation; people with forge access carry out the steps the VTC names, and the VTC governs the rights alone.",
/// "type": "string",
/// "enum": [
/// "bridge",
/// "manual"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum GitNamespaceMode {
#[serde(rename = "bridge")]
Bridge,
#[serde(rename = "manual")]
Manual,
}
impl ::std::fmt::Display for GitNamespaceMode {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Bridge => f.write_str("bridge"),
Self::Manual => f.write_str("manual"),
}
}
}
impl ::std::str::FromStr for GitNamespaceMode {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"bridge" => Ok(Self::Bridge),
"manual" => Ok(Self::Manual),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for GitNamespaceMode {
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 GitNamespaceMode {
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 GitNamespaceMode {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///`pending` — binding has started and the forge-side proof has not arrived yet. `bound` — the VTC governs rights under this namespace.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "`pending` — binding has started and the forge-side proof has not arrived yet. `bound` — the VTC governs rights under this namespace.",
/// "type": "string",
/// "enum": [
/// "pending",
/// "bound"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum GitNamespaceState {
#[serde(rename = "pending")]
Pending,
#[serde(rename = "bound")]
Bound,
}
impl ::std::fmt::Display for GitNamespaceState {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Pending => f.write_str("pending"),
Self::Bound => f.write_str("bound"),
}
}
}
impl ::std::str::FromStr for GitNamespaceState {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"pending" => Ok(Self::Pending),
"bound" => Ok(Self::Bound),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for GitNamespaceState {
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 GitNamespaceState {
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 GitNamespaceState {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///A forge account linked to the caller's DID with git-ns/account/link, and when the link completed.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "LinkedAccount",
/// "description": "A forge account linked to the caller's DID with git-ns/account/link, and when the link completed.",
/// "type": "object",
/// "required": [
/// "account",
/// "linkedAt"
/// ],
/// "properties": {
/// "account": {
/// "description": "The linked account. `id` is authoritative; `login` is as the forge last reported it.",
/// "$ref": "#/definitions/ForgeAccount"
/// },
/// "linkedAt": {
/// "description": "When the link completed: when the VTC recorded the account against the caller's DID.",
/// "type": "string",
/// "format": "date-time"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct LinkedAccount {
///The linked account. `id` is authoritative; `login` is as the forge last reported it.
pub account: ForgeAccount,
///When the link completed: when the VTC recorded the account against the caller's DID.
#[serde(rename = "linkedAt")]
pub linked_at: ::chrono::DateTime<::chrono::offset::Utc>,
}
impl LinkedAccount {
pub fn builder() -> builder::LinkedAccount {
Default::default()
}
}
///The VTC's opaque identifier for a namespace, assigned when it is bound. Stable for the life of the binding; never reused for another binding.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "NamespaceId",
/// "description": "The VTC's opaque identifier for a namespace, assigned when it is bound. Stable for the life of the binding; never reused for another binding.",
/// "type": "string",
/// "maxLength": 128,
/// "minLength": 1
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct NamespaceId(::std::string::String);
impl ::std::ops::Deref for NamespaceId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<NamespaceId> for ::std::string::String {
fn from(value: NamespaceId) -> Self {
value.0
}
}
impl ::std::str::FromStr for NamespaceId {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 128usize {
return Err("longer than 128 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for NamespaceId {
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 NamespaceId {
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 NamespaceId {
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 NamespaceId {
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 member reads the namespaces, repositories and rights they are entitled to see, optionally narrowed to one resource, together with the forge accounts linked to their own DID. An administrator may instead ask for everything in the namespaces they administer, and either may narrow the rights to break-glass records.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "$id": "https://trusttasks.org/spec/git-ns/view/0.5",
/// "title": "Payload",
/// "description": "A member reads the namespaces, repositories and rights they are entitled to see, optionally narrowed to one resource, together with the forge accounts linked to their own DID. An administrator may instead ask for everything in the namespaces they administer, and either may narrow the rights to break-glass records.",
/// "type": "object",
/// "properties": {
/// "breakGlass": {
/// "description": "`true` narrows `rights` to the records carrying `breakGlass` — ratified ones included — and `namespaces` and `repos` to those that contain such a record. `false` or absent: no narrowing. Absent means `false`; this carries no schema-level default, so a producer that omits it is not normalised into sending it.",
/// "type": "boolean"
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "resource": {
/// "description": "Narrow the answer to this resource and everything inside it. Absent: everything the caller may see.",
/// "$ref": "#/definitions/Resource"
/// },
/// "scope": {
/// "description": "`member` (the default) — what the caller may see through their own git rights, exactly as in 0.4. `administrator` — everything in the namespaces the caller administers (every namespace, for a holder of the community-administrator capability; those they hold `git.ns.admin` on, for anyone else), reasons included. Refused with `git-ns/view:notAdministrator` when the caller administers no namespace within `resource`. Absent means `\"member\"`; this carries no schema-level default, so a producer that omits it is not normalised into sending it.",
/// "type": "string",
/// "enum": [
/// "member",
/// "administrator"
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Payload {
///`true` narrows `rights` to the records carrying `breakGlass` — ratified ones included — and `namespaces` and `repos` to those that contain such a record. `false` or absent: no narrowing. Absent means `false`; this carries no schema-level default, so a producer that omits it is not normalised into sending it.
#[serde(
rename = "breakGlass",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub break_glass: ::std::option::Option<bool>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///Narrow the answer to this resource and everything inside it. Absent: everything the caller may see.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub resource: ::std::option::Option<Resource>,
///`member` (the default) — what the caller may see through their own git rights, exactly as in 0.4. `administrator` — everything in the namespaces the caller administers (every namespace, for a holder of the community-administrator capability; those they hold `git.ns.admin` on, for anyone else), reasons included. Refused with `git-ns/view:notAdministrator` when the caller administers no namespace within `resource`. Absent means `"member"`; this carries no schema-level default, so a producer that omits it is not normalised into sending it.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub scope: ::std::option::Option<PayloadScope>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
break_glass: Default::default(),
ext: Default::default(),
resource: Default::default(),
scope: Default::default(),
}
}
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///`member` (the default) — what the caller may see through their own git rights, exactly as in 0.4. `administrator` — everything in the namespaces the caller administers (every namespace, for a holder of the community-administrator capability; those they hold `git.ns.admin` on, for anyone else), reasons included. Refused with `git-ns/view:notAdministrator` when the caller administers no namespace within `resource`. Absent means `"member"`; this carries no schema-level default, so a producer that omits it is not normalised into sending it.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "`member` (the default) — what the caller may see through their own git rights, exactly as in 0.4. `administrator` — everything in the namespaces the caller administers (every namespace, for a holder of the community-administrator capability; those they hold `git.ns.admin` on, for anyone else), reasons included. Refused with `git-ns/view:notAdministrator` when the caller administers no namespace within `resource`. Absent means `\"member\"`; this carries no schema-level default, so a producer that omits it is not normalised into sending it.",
/// "type": "string",
/// "enum": [
/// "member",
/// "administrator"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum PayloadScope {
#[serde(rename = "member")]
Member,
#[serde(rename = "administrator")]
Administrator,
}
impl ::std::fmt::Display for PayloadScope {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Member => f.write_str("member"),
Self::Administrator => f.write_str("administrator"),
}
}
}
impl ::std::str::FromStr for PayloadScope {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"member" => Ok(Self::Member),
"administrator" => Ok(Self::Administrator),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for PayloadScope {
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 PayloadScope {
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 PayloadScope {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///A forge-qualified resource naming exactly one repository: `<forge-host>/<owner>/<repo>`, lowercase.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "RepoResource",
/// "description": "A forge-qualified resource naming exactly one repository: `<forge-host>/<owner>/<repo>`, lowercase.",
/// "type": "string",
/// "maxLength": 455,
/// "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+/[a-z0-9_-][a-z0-9._-]{0,99}/[a-z0-9_-][a-z0-9._-]{0,99}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct RepoResource(::std::string::String);
impl ::std::ops::Deref for RepoResource {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<RepoResource> for ::std::string::String {
fn from(value: RepoResource) -> Self {
value.0
}
}
impl ::std::str::FromStr for RepoResource {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 455usize {
return Err("longer than 455 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> = ::std::sync::LazyLock::new(
|| {
::regress::Regex::new(
"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+/[a-z0-9_-][a-z0-9._-]{0,99}/[a-z0-9_-][a-z0-9._-]{0,99}$",
)
.unwrap()
},
);
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+/[a-z0-9_-][a-z0-9._-]{0,99}/[a-z0-9_-][a-z0-9._-]{0,99}$\""
.into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for RepoResource {
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 RepoResource {
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 RepoResource {
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 RepoResource {
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())
})
}
}
///One repository as the VTC records it.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "RepoSummary",
/// "description": "One repository as the VTC records it.",
/// "type": "object",
/// "required": [
/// "bootstrap",
/// "owners",
/// "resource",
/// "state",
/// "sync",
/// "visibility"
/// ],
/// "properties": {
/// "bootstrap": {
/// "$ref": "#/definitions/Bootstrap"
/// },
/// "forgeId": {
/// "description": "The forge's repository id. Absent until the forge has confirmed the repository exists (a `pendingCreate` repository, or one adopted in bridge mode before the first inspection).",
/// "$ref": "#/definitions/ForgeId"
/// },
/// "owners": {
/// "description": "The DIDs holding `git.repo.own` on this repository by an explicit grant. Empty only for an `unmanaged` repository, and for an `orphaned` one whose ownership rests with the namespace admins by implication.",
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/Did"
/// },
/// "uniqueItems": true
/// },
/// "resource": {
/// "$ref": "#/definitions/RepoResource"
/// },
/// "state": {
/// "description": "`pendingCreate` — the name is reserved and the repository is not yet confirmed on the forge. `active` — managed. `archived` — archived through git-ns/repo/archive; commit rights on it are revoked. `detached` — no longer governed: its namespace was unbound, or it moved outside the namespace. `orphaned` — its last owner left the community and ownership passed to the namespace admins, who have not yet named a new owner. `unmanaged` — it exists on the forge inside a bound namespace but was never created or adopted through the VTC.",
/// "type": "string",
/// "enum": [
/// "pendingCreate",
/// "active",
/// "archived",
/// "detached",
/// "orphaned",
/// "unmanaged"
/// ]
/// },
/// "sync": {
/// "$ref": "#/definitions/Sync"
/// },
/// "visibility": {
/// "$ref": "#/definitions/RepoVisibility"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct RepoSummary {
pub bootstrap: Bootstrap,
///The forge's repository id. Absent until the forge has confirmed the repository exists (a `pendingCreate` repository, or one adopted in bridge mode before the first inspection).
#[serde(
rename = "forgeId",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub forge_id: ::std::option::Option<ForgeId>,
///The DIDs holding `git.repo.own` on this repository by an explicit grant. Empty only for an `unmanaged` repository, and for an `orphaned` one whose ownership rests with the namespace admins by implication.
pub owners: Vec<Did>,
pub resource: RepoResource,
///`pendingCreate` — the name is reserved and the repository is not yet confirmed on the forge. `active` — managed. `archived` — archived through git-ns/repo/archive; commit rights on it are revoked. `detached` — no longer governed: its namespace was unbound, or it moved outside the namespace. `orphaned` — its last owner left the community and ownership passed to the namespace admins, who have not yet named a new owner. `unmanaged` — it exists on the forge inside a bound namespace but was never created or adopted through the VTC.
pub state: RepoSummaryState,
pub sync: Sync,
pub visibility: RepoVisibility,
}
impl RepoSummary {
pub fn builder() -> builder::RepoSummary {
Default::default()
}
}
///`pendingCreate` — the name is reserved and the repository is not yet confirmed on the forge. `active` — managed. `archived` — archived through git-ns/repo/archive; commit rights on it are revoked. `detached` — no longer governed: its namespace was unbound, or it moved outside the namespace. `orphaned` — its last owner left the community and ownership passed to the namespace admins, who have not yet named a new owner. `unmanaged` — it exists on the forge inside a bound namespace but was never created or adopted through the VTC.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "`pendingCreate` — the name is reserved and the repository is not yet confirmed on the forge. `active` — managed. `archived` — archived through git-ns/repo/archive; commit rights on it are revoked. `detached` — no longer governed: its namespace was unbound, or it moved outside the namespace. `orphaned` — its last owner left the community and ownership passed to the namespace admins, who have not yet named a new owner. `unmanaged` — it exists on the forge inside a bound namespace but was never created or adopted through the VTC.",
/// "type": "string",
/// "enum": [
/// "pendingCreate",
/// "active",
/// "archived",
/// "detached",
/// "orphaned",
/// "unmanaged"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum RepoSummaryState {
#[serde(rename = "pendingCreate")]
PendingCreate,
#[serde(rename = "active")]
Active,
#[serde(rename = "archived")]
Archived,
#[serde(rename = "detached")]
Detached,
#[serde(rename = "orphaned")]
Orphaned,
#[serde(rename = "unmanaged")]
Unmanaged,
}
impl ::std::fmt::Display for RepoSummaryState {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::PendingCreate => f.write_str("pendingCreate"),
Self::Active => f.write_str("active"),
Self::Archived => f.write_str("archived"),
Self::Detached => f.write_str("detached"),
Self::Orphaned => f.write_str("orphaned"),
Self::Unmanaged => f.write_str("unmanaged"),
}
}
}
impl ::std::str::FromStr for RepoSummaryState {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"pendingCreate" => Ok(Self::PendingCreate),
"active" => Ok(Self::Active),
"archived" => Ok(Self::Archived),
"detached" => Ok(Self::Detached),
"orphaned" => Ok(Self::Orphaned),
"unmanaged" => Ok(Self::Unmanaged),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for RepoSummaryState {
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 RepoSummaryState {
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 RepoSummaryState {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///Repository visibility on the forge.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "RepoVisibility",
/// "description": "Repository visibility on the forge.",
/// "type": "string",
/// "enum": [
/// "public",
/// "private"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum RepoVisibility {
#[serde(rename = "public")]
Public,
#[serde(rename = "private")]
Private,
}
impl ::std::fmt::Display for RepoVisibility {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::Public => f.write_str("public"),
Self::Private => f.write_str("private"),
}
}
}
impl ::std::str::FromStr for RepoVisibility {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"public" => Ok(Self::Public),
"private" => Ok(Self::Private),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for RepoVisibility {
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 RepoVisibility {
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 RepoVisibility {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///A forge-qualified resource: `<forge-host>/<owner>` for a namespace, or `<forge-host>/<owner>/<repo>` for one repository, all lowercase — `github.com/acme`, `github.com/acme/widgets`, `codeberg.org/acme`. The forge is never implied: `acme/widgets` alone is not a resource. Containment is by whole segment: `github.com/acme` contains `github.com/acme/widgets` and does not contain `github.com/acme-labs/x` or `codeberg.org/acme/widgets`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Resource",
/// "description": "A forge-qualified resource: `<forge-host>/<owner>` for a namespace, or `<forge-host>/<owner>/<repo>` for one repository, all lowercase — `github.com/acme`, `github.com/acme/widgets`, `codeberg.org/acme`. The forge is never implied: `acme/widgets` alone is not a resource. Containment is by whole segment: `github.com/acme` contains `github.com/acme/widgets` and does not contain `github.com/acme-labs/x` or `codeberg.org/acme/widgets`.",
/// "type": "string",
/// "maxLength": 455,
/// "pattern": "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+(?:/[a-z0-9_-][a-z0-9._-]{0,99}){1,2}$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct Resource(::std::string::String);
impl ::std::ops::Deref for Resource {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<Resource> for ::std::string::String {
fn from(value: Resource) -> Self {
value.0
}
}
impl ::std::str::FromStr for Resource {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 455usize {
return Err("longer than 455 characters".into());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> = ::std::sync::LazyLock::new(
|| {
::regress::Regex::new(
"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+(?:/[a-z0-9_-][a-z0-9._-]{0,99}){1,2}$",
)
.unwrap()
},
);
if PATTERN.find(value).is_none() {
return Err(
"doesn't match pattern \"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+(?:/[a-z0-9_-][a-z0-9._-]{0,99}){1,2}$\""
.into(),
);
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for Resource {
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 Resource {
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 Resource {
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 Resource {
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())
})
}
}
///What the caller may see — or, with `scope: administrator`, everything in the namespaces they administer — and the caller's own linked forge accounts.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Response",
/// "description": "What the caller may see — or, with `scope: administrator`, everything in the namespaces they administer — and the caller's own linked forge accounts.",
/// "type": "object",
/// "required": [
/// "accounts",
/// "namespaces",
/// "repos",
/// "rights"
/// ],
/// "properties": {
/// "accounts": {
/// "description": "The forge accounts linked to the caller's own DID — never another member's — at most one per forge. With `resource`, only the account on that resource's forge. Empty when the caller has linked none.",
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/LinkedAccount"
/// }
/// },
/// "ext": {
/// "$ref": "#/definitions/Ext"
/// },
/// "namespaces": {
/// "description": "Namespaces bound to this VTC that contain, or are contained by, `resource`. With `scope: administrator`, only those the caller administers. With `breakGlass: true`, only those containing a returned record.",
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/GitNamespace"
/// }
/// },
/// "repos": {
/// "description": "Repositories within `resource`. `unmanaged` repositories are included only for callers holding `git.ns.admin` over them, or with `scope: administrator`. With `breakGlass: true`, only those carrying a returned record.",
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/RepoSummary"
/// }
/// },
/// "rights": {
/// "description": "Rights within `resource` the caller may see: always the caller's own; every right on a resource the caller owns or administers; every unratified break-glass record in a namespace they administer or on a resource they own. With `scope: administrator`, every recorded right in the namespaces the caller administers. `reason` is omitted except on resources the caller owns or administers. With `breakGlass: true`, only records carrying `breakGlass`.",
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/RightRecord"
/// }
/// }
/// },
/// "additionalProperties": false,
/// "$anchor": "response"
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Response {
///The forge accounts linked to the caller's own DID — never another member's — at most one per forge. With `resource`, only the account on that resource's forge. Empty when the caller has linked none.
pub accounts: ::std::vec::Vec<LinkedAccount>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///Namespaces bound to this VTC that contain, or are contained by, `resource`. With `scope: administrator`, only those the caller administers. With `breakGlass: true`, only those containing a returned record.
pub namespaces: ::std::vec::Vec<GitNamespace>,
///Repositories within `resource`. `unmanaged` repositories are included only for callers holding `git.ns.admin` over them, or with `scope: administrator`. With `breakGlass: true`, only those carrying a returned record.
pub repos: ::std::vec::Vec<RepoSummary>,
///Rights within `resource` the caller may see: always the caller's own; every right on a resource the caller owns or administers; every unratified break-glass record in a namespace they administer or on a resource they own. With `scope: administrator`, every recorded right in the namespaces the caller administers. `reason` is omitted except on resources the caller owns or administers. With `breakGlass: true`, only records carrying `breakGlass`.
pub rights: ::std::vec::Vec<RightRecord>,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
///One of the five git rights. Each string is also the TRQP `action` the VTC publishes the right under in its Trust Registry, so it is carried verbatim. `git.ns.admin` and `git.repo.create` apply to a namespace resource; `git.repo.own` and `git.repo.maintain` to a repository resource; `git.commit.sign` to either.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Right",
/// "description": "One of the five git rights. Each string is also the TRQP `action` the VTC publishes the right under in its Trust Registry, so it is carried verbatim. `git.ns.admin` and `git.repo.create` apply to a namespace resource; `git.repo.own` and `git.repo.maintain` to a repository resource; `git.commit.sign` to either.",
/// "type": "string",
/// "enum": [
/// "git.ns.admin",
/// "git.repo.create",
/// "git.repo.own",
/// "git.repo.maintain",
/// "git.commit.sign"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum Right {
#[serde(rename = "git.ns.admin")]
GitNsAdmin,
#[serde(rename = "git.repo.create")]
GitRepoCreate,
#[serde(rename = "git.repo.own")]
GitRepoOwn,
#[serde(rename = "git.repo.maintain")]
GitRepoMaintain,
#[serde(rename = "git.commit.sign")]
GitCommitSign,
}
impl ::std::fmt::Display for Right {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::GitNsAdmin => f.write_str("git.ns.admin"),
Self::GitRepoCreate => f.write_str("git.repo.create"),
Self::GitRepoOwn => f.write_str("git.repo.own"),
Self::GitRepoMaintain => f.write_str("git.repo.maintain"),
Self::GitCommitSign => f.write_str("git.commit.sign"),
}
}
}
impl ::std::str::FromStr for Right {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"git.ns.admin" => Ok(Self::GitNsAdmin),
"git.repo.create" => Ok(Self::GitRepoCreate),
"git.repo.own" => Ok(Self::GitRepoOwn),
"git.repo.maintain" => Ok(Self::GitRepoMaintain),
"git.commit.sign" => Ok(Self::GitCommitSign),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for Right {
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 Right {
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 Right {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
///One recorded right. Implied rights (§4.2 of the rights model: `own` implies `maintain` implies `commit.sign` on the same resource; `ns.admin` implies `repo.create` and `own` across its namespace) are not records and never appear as RightRecords. A record carrying `breakGlass` was given by its subject to themselves through git-ns/right/break-glass; it is a real right, published like any other, and is shown with that flag on every surface that shows the record.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "RightRecord",
/// "description": "One recorded right. Implied rights (§4.2 of the rights model: `own` implies `maintain` implies `commit.sign` on the same resource; `ns.admin` implies `repo.create` and `own` across its namespace) are not records and never appear as RightRecords. A record carrying `breakGlass` was given by its subject to themselves through git-ns/right/break-glass; it is a real right, published like any other, and is shown with that flag on every surface that shows the record.",
/// "type": "object",
/// "required": [
/// "grantedAt",
/// "grantedBy",
/// "resource",
/// "right",
/// "subject"
/// ],
/// "properties": {
/// "breakGlass": {
/// "description": "Present exactly when the subject gave themselves this right through git-ns/right/break-glass. Absent for every other record.",
/// "$ref": "#/definitions/BreakGlass"
/// },
/// "expiresAt": {
/// "description": "When the right lapses. Absent: no expiry.",
/// "type": "string",
/// "format": "date-time"
/// },
/// "grantedAt": {
/// "type": "string",
/// "format": "date-time"
/// },
/// "grantedBy": {
/// "description": "The actor whose task caused the right: the granter, the creator of a repository (for its first `own`), the adopting admin, the transferring owner, or the binding admin (for the first `git.ns.admin`). The VTC's own DID for a right it derives from its configuration.",
/// "$ref": "#/definitions/Did"
/// },
/// "reason": {
/// "description": "The granter's free-text reason. Disclosed only to holders of `git.repo.own` on the resource and of `git.ns.admin` over it.",
/// "type": "string",
/// "maxLength": 1024
/// },
/// "resource": {
/// "$ref": "#/definitions/Resource"
/// },
/// "right": {
/// "$ref": "#/definitions/Right"
/// },
/// "subject": {
/// "description": "Who holds the right. For `git.commit.sign` this is the DID whose commit signatures the CI check accepts.",
/// "$ref": "#/definitions/Did"
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct RightRecord {
///Present exactly when the subject gave themselves this right through git-ns/right/break-glass. Absent for every other record.
#[serde(
rename = "breakGlass",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub break_glass: ::std::option::Option<BreakGlass>,
///When the right lapses. Absent: no expiry.
#[serde(
rename = "expiresAt",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub expires_at: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
#[serde(rename = "grantedAt")]
pub granted_at: ::chrono::DateTime<::chrono::offset::Utc>,
///The actor whose task caused the right: the granter, the creator of a repository (for its first `own`), the adopting admin, the transferring owner, or the binding admin (for the first `git.ns.admin`). The VTC's own DID for a right it derives from its configuration.
#[serde(rename = "grantedBy")]
pub granted_by: Did,
///The granter's free-text reason. Disclosed only to holders of `git.repo.own` on the resource and of `git.ns.admin` over it.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub reason: ::std::option::Option<RightRecordReason>,
pub resource: Resource,
pub right: Right,
///Who holds the right. For `git.commit.sign` this is the DID whose commit signatures the CI check accepts.
pub subject: Did,
}
impl RightRecord {
pub fn builder() -> builder::RightRecord {
Default::default()
}
}
///The granter's free-text reason. Disclosed only to holders of `git.repo.own` on the resource and of `git.ns.admin` over it.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "The granter's free-text reason. Disclosed only to holders of `git.repo.own` on the resource and of `git.ns.admin` over it.",
/// "type": "string",
/// "maxLength": 1024
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct RightRecordReason(::std::string::String);
impl ::std::ops::Deref for RightRecordReason {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<RightRecordReason> for ::std::string::String {
fn from(value: RightRecordReason) -> Self {
value.0
}
}
impl ::std::str::FromStr for RightRecordReason {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 1024usize {
return Err("longer than 1024 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for RightRecordReason {
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 RightRecordReason {
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 RightRecordReason {
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 RightRecordReason {
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())
})
}
}
///One lowercased owner or repository name. Forges compare these case-insensitively, so the wire form is always lowercase and a producer lowercases before sending. A leading `.` is refused, which rules out `.` and `..`.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Segment",
/// "description": "One lowercased owner or repository name. Forges compare these case-insensitively, so the wire form is always lowercase and a producer lowercases before sending. A leading `.` is refused, which rules out `.` and `..`.",
/// "type": "string",
/// "maxLength": 100,
/// "minLength": 1,
/// "pattern": "^[a-z0-9_-][a-z0-9._-]*$"
///}
/// ```
/// </details>
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct Segment(::std::string::String);
impl ::std::ops::Deref for Segment {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<Segment> for ::std::string::String {
fn from(value: Segment) -> Self {
value.0
}
}
impl ::std::str::FromStr for Segment {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 100usize {
return Err("longer than 100 characters".into());
}
if value.chars().count() < 1usize {
return Err("shorter than 1 characters".into());
}
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 Segment {
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 Segment {
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 Segment {
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 Segment {
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())
})
}
}
///How the forge compares with the VTC's projection for one repository.
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "title": "Sync",
/// "description": "How the forge compares with the VTC's projection for one repository.",
/// "type": "object",
/// "required": [
/// "drift",
/// "state"
/// ],
/// "properties": {
/// "checkedAt": {
/// "description": "When the forge was last compared. Absent if never.",
/// "type": "string",
/// "format": "date-time"
/// },
/// "drift": {
/// "description": "Outstanding drift. Empty unless `state` is `drift`.",
/// "type": "array",
/// "items": {
/// "$ref": "#/definitions/DriftItem"
/// }
/// },
/// "state": {
/// "description": "`inSync` — the last comparison found no drift. `drift` — it found some, listed in `drift`. `pending` — a change has been sent to the forge and not yet confirmed. `unchecked` — nothing compares this repository (a manual-mode namespace).",
/// "type": "string",
/// "enum": [
/// "inSync",
/// "drift",
/// "pending",
/// "unchecked"
/// ]
/// }
/// },
/// "additionalProperties": false
///}
/// ```
/// </details>
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct Sync {
///When the forge was last compared. Absent if never.
#[serde(
rename = "checkedAt",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub checked_at: ::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
///Outstanding drift. Empty unless `state` is `drift`.
pub drift: ::std::vec::Vec<DriftItem>,
///`inSync` — the last comparison found no drift. `drift` — it found some, listed in `drift`. `pending` — a change has been sent to the forge and not yet confirmed. `unchecked` — nothing compares this repository (a manual-mode namespace).
pub state: SyncState,
}
impl Sync {
pub fn builder() -> builder::Sync {
Default::default()
}
}
///`inSync` — the last comparison found no drift. `drift` — it found some, listed in `drift`. `pending` — a change has been sent to the forge and not yet confirmed. `unchecked` — nothing compares this repository (a manual-mode namespace).
///
/// <details><summary>JSON schema</summary>
///
/// ```json
///{
/// "description": "`inSync` — the last comparison found no drift. `drift` — it found some, listed in `drift`. `pending` — a change has been sent to the forge and not yet confirmed. `unchecked` — nothing compares this repository (a manual-mode namespace).",
/// "type": "string",
/// "enum": [
/// "inSync",
/// "drift",
/// "pending",
/// "unchecked"
/// ]
///}
/// ```
/// </details>
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum SyncState {
#[serde(rename = "inSync")]
InSync,
#[serde(rename = "drift")]
Drift,
#[serde(rename = "pending")]
Pending,
#[serde(rename = "unchecked")]
Unchecked,
}
impl ::std::fmt::Display for SyncState {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::InSync => f.write_str("inSync"),
Self::Drift => f.write_str("drift"),
Self::Pending => f.write_str("pending"),
Self::Unchecked => f.write_str("unchecked"),
}
}
}
impl ::std::str::FromStr for SyncState {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"inSync" => Ok(Self::InSync),
"drift" => Ok(Self::Drift),
"pending" => Ok(Self::Pending),
"unchecked" => Ok(Self::Unchecked),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for SyncState {
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 SyncState {
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 SyncState {
type Error = self::error::ConversionError;
fn try_from(
value: ::std::string::String,
) -> ::std::result::Result<Self, self::error::ConversionError> {
value.parse()
}
}
/// Types for composing complex structures.
pub mod builder {
#[derive(Clone, Debug)]
pub struct Bootstrap {
keyring: ::std::result::Result<bool, ::std::string::String>,
required_check: ::std::result::Result<bool, ::std::string::String>,
variables: ::std::result::Result<bool, ::std::string::String>,
workflow: ::std::result::Result<bool, ::std::string::String>,
}
impl ::std::default::Default for Bootstrap {
fn default() -> Self {
Self {
keyring: Err("no value supplied for keyring".to_string()),
required_check: Err("no value supplied for required_check".to_string()),
variables: Err("no value supplied for variables".to_string()),
workflow: Err("no value supplied for workflow".to_string()),
}
}
}
impl Bootstrap {
pub fn keyring<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<bool>,
T::Error: ::std::fmt::Display,
{
self.keyring = value
.try_into()
.map_err(|e| format!("error converting supplied value for keyring: {e}"));
self
}
pub fn required_check<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<bool>,
T::Error: ::std::fmt::Display,
{
self.required_check = value
.try_into()
.map_err(|e| format!("error converting supplied value for required_check: {e}"));
self
}
pub fn variables<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<bool>,
T::Error: ::std::fmt::Display,
{
self.variables = value
.try_into()
.map_err(|e| format!("error converting supplied value for variables: {e}"));
self
}
pub fn workflow<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<bool>,
T::Error: ::std::fmt::Display,
{
self.workflow = value
.try_into()
.map_err(|e| format!("error converting supplied value for workflow: {e}"));
self
}
}
impl ::std::convert::TryFrom<Bootstrap> for super::Bootstrap {
type Error = super::error::ConversionError;
fn try_from(
value: Bootstrap,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
keyring: value.keyring?,
required_check: value.required_check?,
variables: value.variables?,
workflow: value.workflow?,
})
}
}
impl ::std::convert::From<super::Bootstrap> for Bootstrap {
fn from(value: super::Bootstrap) -> Self {
Self {
keyring: Ok(value.keyring),
required_check: Ok(value.required_check),
variables: Ok(value.variables),
workflow: Ok(value.workflow),
}
}
}
#[derive(Clone, Debug)]
pub struct BreakGlass {
at: ::std::result::Result<::chrono::DateTime<::chrono::offset::Utc>, ::std::string::String>,
by: ::std::result::Result<super::Did, ::std::string::String>,
effective_at: ::std::result::Result<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
::std::string::String,
>,
justification: ::std::result::Result<super::BreakGlassJustification, ::std::string::String>,
ratified_at: ::std::result::Result<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
::std::string::String,
>,
ratified_by:
::std::result::Result<::std::option::Option<super::Did>, ::std::string::String>,
}
impl ::std::default::Default for BreakGlass {
fn default() -> Self {
Self {
at: Err("no value supplied for at".to_string()),
by: Err("no value supplied for by".to_string()),
effective_at: Ok(Default::default()),
justification: Err("no value supplied for justification".to_string()),
ratified_at: Ok(Default::default()),
ratified_by: Ok(Default::default()),
}
}
}
impl BreakGlass {
pub fn at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::chrono::DateTime<::chrono::offset::Utc>>,
T::Error: ::std::fmt::Display,
{
self.at = value
.try_into()
.map_err(|e| format!("error converting supplied value for at: {e}"));
self
}
pub fn by<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Did>,
T::Error: ::std::fmt::Display,
{
self.by = value
.try_into()
.map_err(|e| format!("error converting supplied value for by: {e}"));
self
}
pub fn effective_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
>,
T::Error: ::std::fmt::Display,
{
self.effective_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for effective_at: {e}"));
self
}
pub fn justification<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::BreakGlassJustification>,
T::Error: ::std::fmt::Display,
{
self.justification = value
.try_into()
.map_err(|e| format!("error converting supplied value for justification: {e}"));
self
}
pub fn ratified_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
>,
T::Error: ::std::fmt::Display,
{
self.ratified_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for ratified_at: {e}"));
self
}
pub fn ratified_by<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Did>>,
T::Error: ::std::fmt::Display,
{
self.ratified_by = value
.try_into()
.map_err(|e| format!("error converting supplied value for ratified_by: {e}"));
self
}
}
impl ::std::convert::TryFrom<BreakGlass> for super::BreakGlass {
type Error = super::error::ConversionError;
fn try_from(
value: BreakGlass,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
at: value.at?,
by: value.by?,
effective_at: value.effective_at?,
justification: value.justification?,
ratified_at: value.ratified_at?,
ratified_by: value.ratified_by?,
})
}
}
impl ::std::convert::From<super::BreakGlass> for BreakGlass {
fn from(value: super::BreakGlass) -> Self {
Self {
at: Ok(value.at),
by: Ok(value.by),
effective_at: Ok(value.effective_at),
justification: Ok(value.justification),
ratified_at: Ok(value.ratified_at),
ratified_by: Ok(value.ratified_by),
}
}
}
#[derive(Clone, Debug)]
pub struct DriftItem {
account: ::std::result::Result<
::std::option::Option<super::ForgeAccount>,
::std::string::String,
>,
expected: ::std::result::Result<
::std::option::Option<super::DriftItemExpected>,
::std::string::String,
>,
observed: ::std::result::Result<
::std::option::Option<super::DriftItemObserved>,
::std::string::String,
>,
resource: ::std::result::Result<super::RepoResource, ::std::string::String>,
type_: ::std::result::Result<super::DriftItemType, ::std::string::String>,
}
impl ::std::default::Default for DriftItem {
fn default() -> Self {
Self {
account: Ok(Default::default()),
expected: Ok(Default::default()),
observed: Ok(Default::default()),
resource: Err("no value supplied for resource".to_string()),
type_: Err("no value supplied for type_".to_string()),
}
}
}
impl DriftItem {
pub fn account<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ForgeAccount>>,
T::Error: ::std::fmt::Display,
{
self.account = value
.try_into()
.map_err(|e| format!("error converting supplied value for account: {e}"));
self
}
pub fn expected<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::DriftItemExpected>>,
T::Error: ::std::fmt::Display,
{
self.expected = value
.try_into()
.map_err(|e| format!("error converting supplied value for expected: {e}"));
self
}
pub fn observed<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::DriftItemObserved>>,
T::Error: ::std::fmt::Display,
{
self.observed = value
.try_into()
.map_err(|e| format!("error converting supplied value for observed: {e}"));
self
}
pub fn resource<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::RepoResource>,
T::Error: ::std::fmt::Display,
{
self.resource = value
.try_into()
.map_err(|e| format!("error converting supplied value for resource: {e}"));
self
}
pub fn type_<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::DriftItemType>,
T::Error: ::std::fmt::Display,
{
self.type_ = value
.try_into()
.map_err(|e| format!("error converting supplied value for type_: {e}"));
self
}
}
impl ::std::convert::TryFrom<DriftItem> for super::DriftItem {
type Error = super::error::ConversionError;
fn try_from(
value: DriftItem,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
account: value.account?,
expected: value.expected?,
observed: value.observed?,
resource: value.resource?,
type_: value.type_?,
})
}
}
impl ::std::convert::From<super::DriftItem> for DriftItem {
fn from(value: super::DriftItem) -> Self {
Self {
account: Ok(value.account),
expected: Ok(value.expected),
observed: Ok(value.observed),
resource: Ok(value.resource),
type_: Ok(value.type_),
}
}
}
#[derive(Clone, Debug)]
pub struct ForgeAccount {
forge: ::std::result::Result<super::ForgeHost, ::std::string::String>,
id: ::std::result::Result<super::ForgeId, ::std::string::String>,
login: ::std::result::Result<super::ForgeAccountLogin, ::std::string::String>,
}
impl ::std::default::Default for ForgeAccount {
fn default() -> Self {
Self {
forge: Err("no value supplied for forge".to_string()),
id: Err("no value supplied for id".to_string()),
login: Err("no value supplied for login".to_string()),
}
}
}
impl ForgeAccount {
pub fn forge<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ForgeHost>,
T::Error: ::std::fmt::Display,
{
self.forge = value
.try_into()
.map_err(|e| format!("error converting supplied value for forge: {e}"));
self
}
pub fn id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ForgeId>,
T::Error: ::std::fmt::Display,
{
self.id = value
.try_into()
.map_err(|e| format!("error converting supplied value for id: {e}"));
self
}
pub fn login<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ForgeAccountLogin>,
T::Error: ::std::fmt::Display,
{
self.login = value
.try_into()
.map_err(|e| format!("error converting supplied value for login: {e}"));
self
}
}
impl ::std::convert::TryFrom<ForgeAccount> for super::ForgeAccount {
type Error = super::error::ConversionError;
fn try_from(
value: ForgeAccount,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
forge: value.forge?,
id: value.id?,
login: value.login?,
})
}
}
impl ::std::convert::From<super::ForgeAccount> for ForgeAccount {
fn from(value: super::ForgeAccount) -> Self {
Self {
forge: Ok(value.forge),
id: Ok(value.id),
login: Ok(value.login),
}
}
}
#[derive(Clone, Debug)]
pub struct GitNamespace {
forge: ::std::result::Result<super::ForgeHost, ::std::string::String>,
id: ::std::result::Result<super::NamespaceId, ::std::string::String>,
kind: ::std::result::Result<
::std::option::Option<super::GitNamespaceKind>,
::std::string::String,
>,
mode: ::std::result::Result<super::GitNamespaceMode, ::std::string::String>,
owner: ::std::result::Result<super::Segment, ::std::string::String>,
state: ::std::result::Result<super::GitNamespaceState, ::std::string::String>,
}
impl ::std::default::Default for GitNamespace {
fn default() -> Self {
Self {
forge: Err("no value supplied for forge".to_string()),
id: Err("no value supplied for id".to_string()),
kind: Ok(Default::default()),
mode: Err("no value supplied for mode".to_string()),
owner: Err("no value supplied for owner".to_string()),
state: Err("no value supplied for state".to_string()),
}
}
}
impl GitNamespace {
pub fn forge<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ForgeHost>,
T::Error: ::std::fmt::Display,
{
self.forge = value
.try_into()
.map_err(|e| format!("error converting supplied value for forge: {e}"));
self
}
pub fn id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::NamespaceId>,
T::Error: ::std::fmt::Display,
{
self.id = value
.try_into()
.map_err(|e| format!("error converting supplied value for id: {e}"));
self
}
pub fn kind<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::GitNamespaceKind>>,
T::Error: ::std::fmt::Display,
{
self.kind = value
.try_into()
.map_err(|e| format!("error converting supplied value for kind: {e}"));
self
}
pub fn mode<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::GitNamespaceMode>,
T::Error: ::std::fmt::Display,
{
self.mode = value
.try_into()
.map_err(|e| format!("error converting supplied value for mode: {e}"));
self
}
pub fn owner<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Segment>,
T::Error: ::std::fmt::Display,
{
self.owner = value
.try_into()
.map_err(|e| format!("error converting supplied value for owner: {e}"));
self
}
pub fn state<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::GitNamespaceState>,
T::Error: ::std::fmt::Display,
{
self.state = value
.try_into()
.map_err(|e| format!("error converting supplied value for state: {e}"));
self
}
}
impl ::std::convert::TryFrom<GitNamespace> for super::GitNamespace {
type Error = super::error::ConversionError;
fn try_from(
value: GitNamespace,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
forge: value.forge?,
id: value.id?,
kind: value.kind?,
mode: value.mode?,
owner: value.owner?,
state: value.state?,
})
}
}
impl ::std::convert::From<super::GitNamespace> for GitNamespace {
fn from(value: super::GitNamespace) -> Self {
Self {
forge: Ok(value.forge),
id: Ok(value.id),
kind: Ok(value.kind),
mode: Ok(value.mode),
owner: Ok(value.owner),
state: Ok(value.state),
}
}
}
#[derive(Clone, Debug)]
pub struct LinkedAccount {
account: ::std::result::Result<super::ForgeAccount, ::std::string::String>,
linked_at:
::std::result::Result<::chrono::DateTime<::chrono::offset::Utc>, ::std::string::String>,
}
impl ::std::default::Default for LinkedAccount {
fn default() -> Self {
Self {
account: Err("no value supplied for account".to_string()),
linked_at: Err("no value supplied for linked_at".to_string()),
}
}
}
impl LinkedAccount {
pub fn account<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::ForgeAccount>,
T::Error: ::std::fmt::Display,
{
self.account = value
.try_into()
.map_err(|e| format!("error converting supplied value for account: {e}"));
self
}
pub fn linked_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::chrono::DateTime<::chrono::offset::Utc>>,
T::Error: ::std::fmt::Display,
{
self.linked_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for linked_at: {e}"));
self
}
}
impl ::std::convert::TryFrom<LinkedAccount> for super::LinkedAccount {
type Error = super::error::ConversionError;
fn try_from(
value: LinkedAccount,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
account: value.account?,
linked_at: value.linked_at?,
})
}
}
impl ::std::convert::From<super::LinkedAccount> for LinkedAccount {
fn from(value: super::LinkedAccount) -> Self {
Self {
account: Ok(value.account),
linked_at: Ok(value.linked_at),
}
}
}
#[derive(Clone, Debug)]
pub struct Payload {
break_glass: ::std::result::Result<::std::option::Option<bool>, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
resource:
::std::result::Result<::std::option::Option<super::Resource>, ::std::string::String>,
scope: ::std::result::Result<
::std::option::Option<super::PayloadScope>,
::std::string::String,
>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
break_glass: Ok(Default::default()),
ext: Ok(Default::default()),
resource: Ok(Default::default()),
scope: Ok(Default::default()),
}
}
}
impl Payload {
pub fn break_glass<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<bool>>,
T::Error: ::std::fmt::Display,
{
self.break_glass = value
.try_into()
.map_err(|e| format!("error converting supplied value for break_glass: {e}"));
self
}
pub fn ext<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ext>>,
T::Error: ::std::fmt::Display,
{
self.ext = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext: {e}"));
self
}
pub fn resource<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Resource>>,
T::Error: ::std::fmt::Display,
{
self.resource = value
.try_into()
.map_err(|e| format!("error converting supplied value for resource: {e}"));
self
}
pub fn scope<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::PayloadScope>>,
T::Error: ::std::fmt::Display,
{
self.scope = value
.try_into()
.map_err(|e| format!("error converting supplied value for scope: {e}"));
self
}
}
impl ::std::convert::TryFrom<Payload> for super::Payload {
type Error = super::error::ConversionError;
fn try_from(value: Payload) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
break_glass: value.break_glass?,
ext: value.ext?,
resource: value.resource?,
scope: value.scope?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
break_glass: Ok(value.break_glass),
ext: Ok(value.ext),
resource: Ok(value.resource),
scope: Ok(value.scope),
}
}
}
#[derive(Clone, Debug)]
pub struct RepoSummary {
bootstrap: ::std::result::Result<super::Bootstrap, ::std::string::String>,
forge_id:
::std::result::Result<::std::option::Option<super::ForgeId>, ::std::string::String>,
owners: ::std::result::Result<Vec<super::Did>, ::std::string::String>,
resource: ::std::result::Result<super::RepoResource, ::std::string::String>,
state: ::std::result::Result<super::RepoSummaryState, ::std::string::String>,
sync: ::std::result::Result<super::Sync, ::std::string::String>,
visibility: ::std::result::Result<super::RepoVisibility, ::std::string::String>,
}
impl ::std::default::Default for RepoSummary {
fn default() -> Self {
Self {
bootstrap: Err("no value supplied for bootstrap".to_string()),
forge_id: Ok(Default::default()),
owners: Err("no value supplied for owners".to_string()),
resource: Err("no value supplied for resource".to_string()),
state: Err("no value supplied for state".to_string()),
sync: Err("no value supplied for sync".to_string()),
visibility: Err("no value supplied for visibility".to_string()),
}
}
}
impl RepoSummary {
pub fn bootstrap<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Bootstrap>,
T::Error: ::std::fmt::Display,
{
self.bootstrap = value
.try_into()
.map_err(|e| format!("error converting supplied value for bootstrap: {e}"));
self
}
pub fn forge_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ForgeId>>,
T::Error: ::std::fmt::Display,
{
self.forge_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for forge_id: {e}"));
self
}
pub fn owners<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<Vec<super::Did>>,
T::Error: ::std::fmt::Display,
{
self.owners = value
.try_into()
.map_err(|e| format!("error converting supplied value for owners: {e}"));
self
}
pub fn resource<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::RepoResource>,
T::Error: ::std::fmt::Display,
{
self.resource = value
.try_into()
.map_err(|e| format!("error converting supplied value for resource: {e}"));
self
}
pub fn state<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::RepoSummaryState>,
T::Error: ::std::fmt::Display,
{
self.state = value
.try_into()
.map_err(|e| format!("error converting supplied value for state: {e}"));
self
}
pub fn sync<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Sync>,
T::Error: ::std::fmt::Display,
{
self.sync = value
.try_into()
.map_err(|e| format!("error converting supplied value for sync: {e}"));
self
}
pub fn visibility<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::RepoVisibility>,
T::Error: ::std::fmt::Display,
{
self.visibility = value
.try_into()
.map_err(|e| format!("error converting supplied value for visibility: {e}"));
self
}
}
impl ::std::convert::TryFrom<RepoSummary> for super::RepoSummary {
type Error = super::error::ConversionError;
fn try_from(
value: RepoSummary,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
bootstrap: value.bootstrap?,
forge_id: value.forge_id?,
owners: value.owners?,
resource: value.resource?,
state: value.state?,
sync: value.sync?,
visibility: value.visibility?,
})
}
}
impl ::std::convert::From<super::RepoSummary> for RepoSummary {
fn from(value: super::RepoSummary) -> Self {
Self {
bootstrap: Ok(value.bootstrap),
forge_id: Ok(value.forge_id),
owners: Ok(value.owners),
resource: Ok(value.resource),
state: Ok(value.state),
sync: Ok(value.sync),
visibility: Ok(value.visibility),
}
}
}
#[derive(Clone, Debug)]
pub struct Response {
accounts:
::std::result::Result<::std::vec::Vec<super::LinkedAccount>, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
namespaces:
::std::result::Result<::std::vec::Vec<super::GitNamespace>, ::std::string::String>,
repos: ::std::result::Result<::std::vec::Vec<super::RepoSummary>, ::std::string::String>,
rights: ::std::result::Result<::std::vec::Vec<super::RightRecord>, ::std::string::String>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
accounts: Err("no value supplied for accounts".to_string()),
ext: Ok(Default::default()),
namespaces: Err("no value supplied for namespaces".to_string()),
repos: Err("no value supplied for repos".to_string()),
rights: Err("no value supplied for rights".to_string()),
}
}
}
impl Response {
pub fn accounts<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::LinkedAccount>>,
T::Error: ::std::fmt::Display,
{
self.accounts = value
.try_into()
.map_err(|e| format!("error converting supplied value for accounts: {e}"));
self
}
pub fn ext<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Ext>>,
T::Error: ::std::fmt::Display,
{
self.ext = value
.try_into()
.map_err(|e| format!("error converting supplied value for ext: {e}"));
self
}
pub fn namespaces<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::GitNamespace>>,
T::Error: ::std::fmt::Display,
{
self.namespaces = value
.try_into()
.map_err(|e| format!("error converting supplied value for namespaces: {e}"));
self
}
pub fn repos<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::RepoSummary>>,
T::Error: ::std::fmt::Display,
{
self.repos = value
.try_into()
.map_err(|e| format!("error converting supplied value for repos: {e}"));
self
}
pub fn rights<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::RightRecord>>,
T::Error: ::std::fmt::Display,
{
self.rights = value
.try_into()
.map_err(|e| format!("error converting supplied value for rights: {e}"));
self
}
}
impl ::std::convert::TryFrom<Response> for super::Response {
type Error = super::error::ConversionError;
fn try_from(value: Response) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
accounts: value.accounts?,
ext: value.ext?,
namespaces: value.namespaces?,
repos: value.repos?,
rights: value.rights?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
accounts: Ok(value.accounts),
ext: Ok(value.ext),
namespaces: Ok(value.namespaces),
repos: Ok(value.repos),
rights: Ok(value.rights),
}
}
}
#[derive(Clone, Debug)]
pub struct RightRecord {
break_glass:
::std::result::Result<::std::option::Option<super::BreakGlass>, ::std::string::String>,
expires_at: ::std::result::Result<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
::std::string::String,
>,
granted_at:
::std::result::Result<::chrono::DateTime<::chrono::offset::Utc>, ::std::string::String>,
granted_by: ::std::result::Result<super::Did, ::std::string::String>,
reason: ::std::result::Result<
::std::option::Option<super::RightRecordReason>,
::std::string::String,
>,
resource: ::std::result::Result<super::Resource, ::std::string::String>,
right: ::std::result::Result<super::Right, ::std::string::String>,
subject: ::std::result::Result<super::Did, ::std::string::String>,
}
impl ::std::default::Default for RightRecord {
fn default() -> Self {
Self {
break_glass: Ok(Default::default()),
expires_at: Ok(Default::default()),
granted_at: Err("no value supplied for granted_at".to_string()),
granted_by: Err("no value supplied for granted_by".to_string()),
reason: Ok(Default::default()),
resource: Err("no value supplied for resource".to_string()),
right: Err("no value supplied for right".to_string()),
subject: Err("no value supplied for subject".to_string()),
}
}
}
impl RightRecord {
pub fn break_glass<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::BreakGlass>>,
T::Error: ::std::fmt::Display,
{
self.break_glass = value
.try_into()
.map_err(|e| format!("error converting supplied value for break_glass: {e}"));
self
}
pub fn expires_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
>,
T::Error: ::std::fmt::Display,
{
self.expires_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for expires_at: {e}"));
self
}
pub fn granted_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::chrono::DateTime<::chrono::offset::Utc>>,
T::Error: ::std::fmt::Display,
{
self.granted_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for granted_at: {e}"));
self
}
pub fn granted_by<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Did>,
T::Error: ::std::fmt::Display,
{
self.granted_by = value
.try_into()
.map_err(|e| format!("error converting supplied value for granted_by: {e}"));
self
}
pub fn reason<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::RightRecordReason>>,
T::Error: ::std::fmt::Display,
{
self.reason = value
.try_into()
.map_err(|e| format!("error converting supplied value for reason: {e}"));
self
}
pub fn resource<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Resource>,
T::Error: ::std::fmt::Display,
{
self.resource = value
.try_into()
.map_err(|e| format!("error converting supplied value for resource: {e}"));
self
}
pub fn right<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Right>,
T::Error: ::std::fmt::Display,
{
self.right = value
.try_into()
.map_err(|e| format!("error converting supplied value for right: {e}"));
self
}
pub fn subject<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::Did>,
T::Error: ::std::fmt::Display,
{
self.subject = value
.try_into()
.map_err(|e| format!("error converting supplied value for subject: {e}"));
self
}
}
impl ::std::convert::TryFrom<RightRecord> for super::RightRecord {
type Error = super::error::ConversionError;
fn try_from(
value: RightRecord,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
break_glass: value.break_glass?,
expires_at: value.expires_at?,
granted_at: value.granted_at?,
granted_by: value.granted_by?,
reason: value.reason?,
resource: value.resource?,
right: value.right?,
subject: value.subject?,
})
}
}
impl ::std::convert::From<super::RightRecord> for RightRecord {
fn from(value: super::RightRecord) -> Self {
Self {
break_glass: Ok(value.break_glass),
expires_at: Ok(value.expires_at),
granted_at: Ok(value.granted_at),
granted_by: Ok(value.granted_by),
reason: Ok(value.reason),
resource: Ok(value.resource),
right: Ok(value.right),
subject: Ok(value.subject),
}
}
}
#[derive(Clone, Debug)]
pub struct Sync {
checked_at: ::std::result::Result<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
::std::string::String,
>,
drift: ::std::result::Result<::std::vec::Vec<super::DriftItem>, ::std::string::String>,
state: ::std::result::Result<super::SyncState, ::std::string::String>,
}
impl ::std::default::Default for Sync {
fn default() -> Self {
Self {
checked_at: Ok(Default::default()),
drift: Err("no value supplied for drift".to_string()),
state: Err("no value supplied for state".to_string()),
}
}
}
impl Sync {
pub fn checked_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<
::std::option::Option<::chrono::DateTime<::chrono::offset::Utc>>,
>,
T::Error: ::std::fmt::Display,
{
self.checked_at = value
.try_into()
.map_err(|e| format!("error converting supplied value for checked_at: {e}"));
self
}
pub fn drift<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::vec::Vec<super::DriftItem>>,
T::Error: ::std::fmt::Display,
{
self.drift = value
.try_into()
.map_err(|e| format!("error converting supplied value for drift: {e}"));
self
}
pub fn state<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::SyncState>,
T::Error: ::std::fmt::Display,
{
self.state = value
.try_into()
.map_err(|e| format!("error converting supplied value for state: {e}"));
self
}
}
impl ::std::convert::TryFrom<Sync> for super::Sync {
type Error = super::error::ConversionError;
fn try_from(value: Sync) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
checked_at: value.checked_at?,
drift: value.drift?,
state: value.state?,
})
}
}
impl ::std::convert::From<super::Sync> for Sync {
fn from(value: super::Sync) -> Self {
Self {
checked_at: Ok(value.checked_at),
drift: Ok(value.drift),
state: Ok(value.state),
}
}
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/git-ns/view/0.5";
const IS_PROOF_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"Bootstrap\": {\n \"additionalProperties\": false,\n \"description\": \"Whether each step that turns commit trust on for a repository is in place, as last reported. A step that this forge's plan does not need reads `true`.\",\n \"properties\": {\n \"keyring\": {\n \"description\": \"The exempt platform keyring for forge-signed merge commits is committed, or the forge's plan does not need one.\",\n \"type\": \"boolean\"\n },\n \"requiredCheck\": {\n \"description\": \"The forge refuses to merge into the default branch unless the verify-trust check passes, with no bypass, and a pull request cannot change what that check runs: an organisation-required workflow, code-owner review of workflow files, or protected workflow paths, as the forge allows.\",\n \"type\": \"boolean\"\n },\n \"variables\": {\n \"description\": \"The repository names the Trust Registry and this VTC as its trust anchors.\",\n \"type\": \"boolean\"\n },\n \"workflow\": {\n \"description\": \"The verify-trust check runs on the repository's pull requests — from a workflow committed to it, or, where the forge supports it, required on it from the namespace's own bridge-managed workflow repository at a pinned commit.\",\n \"type\": \"boolean\"\n }\n },\n \"required\": [\n \"workflow\",\n \"keyring\",\n \"variables\",\n \"requiredCheck\"\n ],\n \"title\": \"Bootstrap\",\n \"type\": \"object\"\n },\n \"BreakGlass\": {\n \"additionalProperties\": false,\n \"description\": \"How a self-granted right came to be, and whether another administrator has since ratified it. A record whose `breakGlass` has no `ratifiedBy` is **unratified**: it is live and published like any other right, it does not count toward the last-owner or last-admin invariants, and any community administrator or namespace admin of its namespace may revoke it. Ratification (git-ns/right/ratify) sets `ratifiedBy` and `ratifiedAt`; from then on the record is an ordinary grant, and `breakGlass` stays as its history. Never published to the Trust Registry.\",\n \"properties\": {\n \"at\": {\n \"description\": \"When the VTC recorded the break-glass.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"by\": {\n \"$ref\": \"#/$defs/Did\",\n \"description\": \"Who broke the glass: always the record's `subject`, restated so the flag reads on its own.\"\n },\n \"effectiveAt\": {\n \"description\": \"When the right takes effect, where the community's policy imposed a delay. Absent: it took effect at `at`. Until this instant the record confers nothing and is not published, and any administrator who may revoke it may do so.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"justification\": {\n \"description\": \"The actor's statement of why nobody else could grant this right. Shown to every community administrator, every namespace admin of the namespace and every owner of the resource; kept in the audit record; never published.\",\n \"maxLength\": 2048,\n \"minLength\": 1,\n \"pattern\": \"\\\\S\",\n \"type\": \"string\"\n },\n \"ratifiedAt\": {\n \"description\": \"When it was ratified. Present exactly when `ratifiedBy` is.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"ratifiedBy\": {\n \"$ref\": \"#/$defs/Did\",\n \"description\": \"The administrator who ratified the record — never its subject. Absent while unratified.\"\n }\n },\n \"required\": [\n \"by\",\n \"at\",\n \"justification\"\n ],\n \"title\": \"BreakGlass\",\n \"type\": \"object\"\n },\n \"Did\": {\n \"description\": \"A bare DID in the W3C DID Core syntax (§3.1): `did:`, a method name of lowercase letters and digits, `:`, and a method-specific id of colon-separated segments drawn from `A-Z a-z 0-9 . - _` and percent-encoded octets, the last segment non-empty. A DID URL is not a DID: no path, query or fragment (`/`, `?`, `#`), so a verification-method id such as `did:key:z6Mk…#z6Mk…` is refused. Compared by exact string equality — no case folding or percent-decoding. A consumer MUST still treat the value as data: the pattern keeps shell metacharacters, whitespace and quotes out of the wire form, but it does not make a DID safe to splice into a command or markup.\",\n \"maxLength\": 2048,\n \"pattern\": \"^did:[a-z0-9]+:(?:(?:[A-Za-z0-9._-]|%[0-9A-Fa-f]{2})*:)*(?:[A-Za-z0-9._-]|%[0-9A-Fa-f]{2})+$\",\n \"title\": \"Did\",\n \"type\": \"string\"\n },\n \"DriftItem\": {\n \"additionalProperties\": false,\n \"description\": \"One difference between the forge's observed state and the VTC's projection of a repository.\",\n \"properties\": {\n \"account\": {\n \"$ref\": \"#/$defs/ForgeAccount\",\n \"description\": \"Whose role differs, for the three role types.\"\n },\n \"expected\": {\n \"description\": \"What the projection calls for, in the forge's own vocabulary. Absent when the projection calls for nothing.\",\n \"maxLength\": 256,\n \"type\": \"string\"\n },\n \"observed\": {\n \"description\": \"What the forge shows, in the forge's own vocabulary (a role name such as `maintain`, a setting name). Absent when nothing is there.\",\n \"maxLength\": 256,\n \"type\": \"string\"\n },\n \"resource\": {\n \"$ref\": \"#/$defs/RepoResource\"\n },\n \"type\": {\n \"description\": \"`roleAdded` — someone holds a forge role the projection does not give them. `roleRemoved` — a projected role is missing. `roleChanged` — a projected role is present at another level. `requiredCheckMissing` — the verify-trust check is no longer required. `protectionWeakened` — branch protection or a ruleset is weaker than the projection in another way (force-push allowed, bypass actors added). `bootstrapMissing` — a bootstrap file or variable is gone.\",\n \"enum\": [\n \"roleAdded\",\n \"roleRemoved\",\n \"roleChanged\",\n \"requiredCheckMissing\",\n \"protectionWeakened\",\n \"bootstrapMissing\"\n ],\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"type\",\n \"resource\"\n ],\n \"title\": \"DriftItem\",\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 \"ForgeAccount\": {\n \"additionalProperties\": false,\n \"description\": \"A person's account on one forge. `id` is authoritative; `login` is for display only, because logins can be renamed and re-registered.\",\n \"properties\": {\n \"forge\": {\n \"$ref\": \"#/$defs/ForgeHost\"\n },\n \"id\": {\n \"$ref\": \"#/$defs/ForgeId\"\n },\n \"login\": {\n \"description\": \"The account's current login, as the forge reported it when last seen. Display only.\",\n \"maxLength\": 100,\n \"minLength\": 1,\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"forge\",\n \"id\",\n \"login\"\n ],\n \"title\": \"ForgeAccount\",\n \"type\": \"object\"\n },\n \"ForgeHost\": {\n \"description\": \"The lowercased DNS host of a forge: `github.com`, a GitHub Enterprise Server host, `codeberg.org`, or a self-hosted Forgejo instance such as `git.example.org`. No scheme, no port, no path. The host is a segment of every resource, so a right never crosses forges.\",\n \"maxLength\": 253,\n \"minLength\": 3,\n \"pattern\": \"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$\",\n \"title\": \"ForgeHost\",\n \"type\": \"string\"\n },\n \"ForgeId\": {\n \"description\": \"An identifier the forge itself assigns — a repository id, a user or organisation id — carried as a string so a forge whose ids are not numbers needs no new version. GitHub and Forgejo ids are decimal integers written as strings (`\\\"812736451\\\"`). Unlike a name, it survives renames and transfers, which is why rights and bindings are keyed by it.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"title\": \"ForgeId\",\n \"type\": \"string\"\n },\n \"GitNamespace\": {\n \"additionalProperties\": false,\n \"description\": \"The VTC's binding to one owner on one forge.\",\n \"properties\": {\n \"forge\": {\n \"$ref\": \"#/$defs/ForgeHost\"\n },\n \"id\": {\n \"$ref\": \"#/$defs/NamespaceId\"\n },\n \"kind\": {\n \"description\": \"Whether the owner is an organisation or a personal account, as the forge reports it. Present once known: a bridge-mode namespace learns it when binding completes, and a manual-mode namespace MAY never learn it.\",\n \"enum\": [\n \"organization\",\n \"user\"\n ],\n \"type\": \"string\"\n },\n \"mode\": {\n \"description\": \"`bridge` — a bridge service acts on the forge for this namespace (creates repositories, projects roles, reports drift). `manual` — no automation; people with forge access carry out the steps the VTC names, and the VTC governs the rights alone.\",\n \"enum\": [\n \"bridge\",\n \"manual\"\n ],\n \"type\": \"string\"\n },\n \"owner\": {\n \"$ref\": \"#/$defs/Segment\",\n \"description\": \"The organisation or user on the forge, lowercased.\"\n },\n \"state\": {\n \"description\": \"`pending` — binding has started and the forge-side proof has not arrived yet. `bound` — the VTC governs rights under this namespace.\",\n \"enum\": [\n \"pending\",\n \"bound\"\n ],\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"id\",\n \"forge\",\n \"owner\",\n \"mode\",\n \"state\"\n ],\n \"title\": \"GitNamespace\",\n \"type\": \"object\"\n },\n \"LinkedAccount\": {\n \"additionalProperties\": false,\n \"description\": \"A forge account linked to the caller's DID with git-ns/account/link, and when the link completed.\",\n \"properties\": {\n \"account\": {\n \"$ref\": \"#/$defs/ForgeAccount\",\n \"description\": \"The linked account. `id` is authoritative; `login` is as the forge last reported it.\"\n },\n \"linkedAt\": {\n \"description\": \"When the link completed: when the VTC recorded the account against the caller's DID.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"account\",\n \"linkedAt\"\n ],\n \"title\": \"LinkedAccount\",\n \"type\": \"object\"\n },\n \"NamespaceId\": {\n \"description\": \"The VTC's opaque identifier for a namespace, assigned when it is bound. Stable for the life of the binding; never reused for another binding.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"title\": \"NamespaceId\",\n \"type\": \"string\"\n },\n \"RepoResource\": {\n \"description\": \"A forge-qualified resource naming exactly one repository: `<forge-host>/<owner>/<repo>`, lowercase.\",\n \"maxLength\": 455,\n \"pattern\": \"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+/[a-z0-9_-][a-z0-9._-]{0,99}/[a-z0-9_-][a-z0-9._-]{0,99}$\",\n \"title\": \"RepoResource\",\n \"type\": \"string\"\n },\n \"RepoSummary\": {\n \"additionalProperties\": false,\n \"description\": \"One repository as the VTC records it.\",\n \"properties\": {\n \"bootstrap\": {\n \"$ref\": \"#/$defs/Bootstrap\"\n },\n \"forgeId\": {\n \"$ref\": \"#/$defs/ForgeId\",\n \"description\": \"The forge's repository id. Absent until the forge has confirmed the repository exists (a `pendingCreate` repository, or one adopted in bridge mode before the first inspection).\"\n },\n \"owners\": {\n \"description\": \"The DIDs holding `git.repo.own` on this repository by an explicit grant. Empty only for an `unmanaged` repository, and for an `orphaned` one whose ownership rests with the namespace admins by implication.\",\n \"items\": {\n \"$ref\": \"#/$defs/Did\"\n },\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"resource\": {\n \"$ref\": \"#/$defs/RepoResource\"\n },\n \"state\": {\n \"description\": \"`pendingCreate` — the name is reserved and the repository is not yet confirmed on the forge. `active` — managed. `archived` — archived through git-ns/repo/archive; commit rights on it are revoked. `detached` — no longer governed: its namespace was unbound, or it moved outside the namespace. `orphaned` — its last owner left the community and ownership passed to the namespace admins, who have not yet named a new owner. `unmanaged` — it exists on the forge inside a bound namespace but was never created or adopted through the VTC.\",\n \"enum\": [\n \"pendingCreate\",\n \"active\",\n \"archived\",\n \"detached\",\n \"orphaned\",\n \"unmanaged\"\n ],\n \"type\": \"string\"\n },\n \"sync\": {\n \"$ref\": \"#/$defs/Sync\"\n },\n \"visibility\": {\n \"$ref\": \"#/$defs/RepoVisibility\"\n }\n },\n \"required\": [\n \"resource\",\n \"visibility\",\n \"state\",\n \"owners\",\n \"bootstrap\",\n \"sync\"\n ],\n \"title\": \"RepoSummary\",\n \"type\": \"object\"\n },\n \"RepoVisibility\": {\n \"description\": \"Repository visibility on the forge.\",\n \"enum\": [\n \"public\",\n \"private\"\n ],\n \"title\": \"RepoVisibility\",\n \"type\": \"string\"\n },\n \"Resource\": {\n \"description\": \"A forge-qualified resource: `<forge-host>/<owner>` for a namespace, or `<forge-host>/<owner>/<repo>` for one repository, all lowercase — `github.com/acme`, `github.com/acme/widgets`, `codeberg.org/acme`. The forge is never implied: `acme/widgets` alone is not a resource. Containment is by whole segment: `github.com/acme` contains `github.com/acme/widgets` and does not contain `github.com/acme-labs/x` or `codeberg.org/acme/widgets`.\",\n \"maxLength\": 455,\n \"pattern\": \"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+(?:/[a-z0-9_-][a-z0-9._-]{0,99}){1,2}$\",\n \"title\": \"Resource\",\n \"type\": \"string\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"What the caller may see — or, with `scope: administrator`, everything in the namespaces they administer — and the caller's own linked forge accounts.\",\n \"properties\": {\n \"accounts\": {\n \"description\": \"The forge accounts linked to the caller's own DID — never another member's — at most one per forge. With `resource`, only the account on that resource's forge. Empty when the caller has linked none.\",\n \"items\": {\n \"$ref\": \"#/$defs/LinkedAccount\"\n },\n \"type\": \"array\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"namespaces\": {\n \"description\": \"Namespaces bound to this VTC that contain, or are contained by, `resource`. With `scope: administrator`, only those the caller administers. With `breakGlass: true`, only those containing a returned record.\",\n \"items\": {\n \"$ref\": \"#/$defs/GitNamespace\"\n },\n \"type\": \"array\"\n },\n \"repos\": {\n \"description\": \"Repositories within `resource`. `unmanaged` repositories are included only for callers holding `git.ns.admin` over them, or with `scope: administrator`. With `breakGlass: true`, only those carrying a returned record.\",\n \"items\": {\n \"$ref\": \"#/$defs/RepoSummary\"\n },\n \"type\": \"array\"\n },\n \"rights\": {\n \"description\": \"Rights within `resource` the caller may see: always the caller's own; every right on a resource the caller owns or administers; every unratified break-glass record in a namespace they administer or on a resource they own. With `scope: administrator`, every recorded right in the namespaces the caller administers. `reason` is omitted except on resources the caller owns or administers. With `breakGlass: true`, only records carrying `breakGlass`.\",\n \"items\": {\n \"$ref\": \"#/$defs/RightRecord\"\n },\n \"type\": \"array\"\n }\n },\n \"required\": [\n \"namespaces\",\n \"repos\",\n \"rights\",\n \"accounts\"\n ],\n \"title\": \"Git Namespaces — View — response payload\",\n \"type\": \"object\"\n },\n \"Right\": {\n \"description\": \"One of the five git rights. Each string is also the TRQP `action` the VTC publishes the right under in its Trust Registry, so it is carried verbatim. `git.ns.admin` and `git.repo.create` apply to a namespace resource; `git.repo.own` and `git.repo.maintain` to a repository resource; `git.commit.sign` to either.\",\n \"enum\": [\n \"git.ns.admin\",\n \"git.repo.create\",\n \"git.repo.own\",\n \"git.repo.maintain\",\n \"git.commit.sign\"\n ],\n \"title\": \"Right\",\n \"type\": \"string\"\n },\n \"RightRecord\": {\n \"additionalProperties\": false,\n \"description\": \"One recorded right. Implied rights (§4.2 of the rights model: `own` implies `maintain` implies `commit.sign` on the same resource; `ns.admin` implies `repo.create` and `own` across its namespace) are not records and never appear as RightRecords. A record carrying `breakGlass` was given by its subject to themselves through git-ns/right/break-glass; it is a real right, published like any other, and is shown with that flag on every surface that shows the record.\",\n \"properties\": {\n \"breakGlass\": {\n \"$ref\": \"#/$defs/BreakGlass\",\n \"description\": \"Present exactly when the subject gave themselves this right through git-ns/right/break-glass. Absent for every other record.\"\n },\n \"expiresAt\": {\n \"description\": \"When the right lapses. Absent: no expiry.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"grantedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"grantedBy\": {\n \"$ref\": \"#/$defs/Did\",\n \"description\": \"The actor whose task caused the right: the granter, the creator of a repository (for its first `own`), the adopting admin, the transferring owner, or the binding admin (for the first `git.ns.admin`). The VTC's own DID for a right it derives from its configuration.\"\n },\n \"reason\": {\n \"description\": \"The granter's free-text reason. Disclosed only to holders of `git.repo.own` on the resource and of `git.ns.admin` over it.\",\n \"maxLength\": 1024,\n \"type\": \"string\"\n },\n \"resource\": {\n \"$ref\": \"#/$defs/Resource\"\n },\n \"right\": {\n \"$ref\": \"#/$defs/Right\"\n },\n \"subject\": {\n \"$ref\": \"#/$defs/Did\",\n \"description\": \"Who holds the right. For `git.commit.sign` this is the DID whose commit signatures the CI check accepts.\"\n }\n },\n \"required\": [\n \"subject\",\n \"right\",\n \"resource\",\n \"grantedBy\",\n \"grantedAt\"\n ],\n \"title\": \"RightRecord\",\n \"type\": \"object\"\n },\n \"Segment\": {\n \"description\": \"One lowercased owner or repository name. Forges compare these case-insensitively, so the wire form is always lowercase and a producer lowercases before sending. A leading `.` is refused, which rules out `.` and `..`.\",\n \"maxLength\": 100,\n \"minLength\": 1,\n \"pattern\": \"^[a-z0-9_-][a-z0-9._-]*$\",\n \"title\": \"Segment\",\n \"type\": \"string\"\n },\n \"Sync\": {\n \"additionalProperties\": false,\n \"description\": \"How the forge compares with the VTC's projection for one repository.\",\n \"properties\": {\n \"checkedAt\": {\n \"description\": \"When the forge was last compared. Absent if never.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"drift\": {\n \"description\": \"Outstanding drift. Empty unless `state` is `drift`.\",\n \"items\": {\n \"$ref\": \"#/$defs/DriftItem\"\n },\n \"type\": \"array\"\n },\n \"state\": {\n \"description\": \"`inSync` — the last comparison found no drift. `drift` — it found some, listed in `drift`. `pending` — a change has been sent to the forge and not yet confirmed. `unchecked` — nothing compares this repository (a manual-mode namespace).\",\n \"enum\": [\n \"inSync\",\n \"drift\",\n \"pending\",\n \"unchecked\"\n ],\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"state\",\n \"drift\"\n ],\n \"title\": \"Sync\",\n \"type\": \"object\"\n }\n },\n \"$id\": \"https://trusttasks.org/spec/git-ns/view/0.5\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"additionalProperties\": false,\n \"description\": \"A member reads the namespaces, repositories and rights they are entitled to see, optionally narrowed to one resource, together with the forge accounts linked to their own DID. An administrator may instead ask for everything in the namespaces they administer, and either may narrow the rights to break-glass records.\",\n \"properties\": {\n \"breakGlass\": {\n \"description\": \"`true` narrows `rights` to the records carrying `breakGlass` — ratified ones included — and `namespaces` and `repos` to those that contain such a record. `false` or absent: no narrowing. Absent means `false`; this carries no schema-level default, so a producer that omits it is not normalised into sending it.\",\n \"type\": \"boolean\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"resource\": {\n \"$ref\": \"#/$defs/Resource\",\n \"description\": \"Narrow the answer to this resource and everything inside it. Absent: everything the caller may see.\"\n },\n \"scope\": {\n \"description\": \"`member` (the default) — what the caller may see through their own git rights, exactly as in 0.4. `administrator` — everything in the namespaces the caller administers (every namespace, for a holder of the community-administrator capability; those they hold `git.ns.admin` on, for anyone else), reasons included. Refused with `git-ns/view:notAdministrator` when the caller administers no namespace within `resource`. Absent means `\\\"member\\\"`; this carries no schema-level default, so a producer that omits it is not normalised into sending it.\",\n \"enum\": [\n \"member\",\n \"administrator\"\n ],\n \"type\": \"string\"\n }\n },\n \"required\": [],\n \"title\": \"Git Namespaces — View — payload\",\n \"type\": \"object\"\n}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/git-ns/view/0.5#response";
const IS_PROOF_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\n \"$defs\": {\n \"Bootstrap\": {\n \"additionalProperties\": false,\n \"description\": \"Whether each step that turns commit trust on for a repository is in place, as last reported. A step that this forge's plan does not need reads `true`.\",\n \"properties\": {\n \"keyring\": {\n \"description\": \"The exempt platform keyring for forge-signed merge commits is committed, or the forge's plan does not need one.\",\n \"type\": \"boolean\"\n },\n \"requiredCheck\": {\n \"description\": \"The forge refuses to merge into the default branch unless the verify-trust check passes, with no bypass, and a pull request cannot change what that check runs: an organisation-required workflow, code-owner review of workflow files, or protected workflow paths, as the forge allows.\",\n \"type\": \"boolean\"\n },\n \"variables\": {\n \"description\": \"The repository names the Trust Registry and this VTC as its trust anchors.\",\n \"type\": \"boolean\"\n },\n \"workflow\": {\n \"description\": \"The verify-trust check runs on the repository's pull requests — from a workflow committed to it, or, where the forge supports it, required on it from the namespace's own bridge-managed workflow repository at a pinned commit.\",\n \"type\": \"boolean\"\n }\n },\n \"required\": [\n \"workflow\",\n \"keyring\",\n \"variables\",\n \"requiredCheck\"\n ],\n \"title\": \"Bootstrap\",\n \"type\": \"object\"\n },\n \"BreakGlass\": {\n \"additionalProperties\": false,\n \"description\": \"How a self-granted right came to be, and whether another administrator has since ratified it. A record whose `breakGlass` has no `ratifiedBy` is **unratified**: it is live and published like any other right, it does not count toward the last-owner or last-admin invariants, and any community administrator or namespace admin of its namespace may revoke it. Ratification (git-ns/right/ratify) sets `ratifiedBy` and `ratifiedAt`; from then on the record is an ordinary grant, and `breakGlass` stays as its history. Never published to the Trust Registry.\",\n \"properties\": {\n \"at\": {\n \"description\": \"When the VTC recorded the break-glass.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"by\": {\n \"$ref\": \"#/$defs/Did\",\n \"description\": \"Who broke the glass: always the record's `subject`, restated so the flag reads on its own.\"\n },\n \"effectiveAt\": {\n \"description\": \"When the right takes effect, where the community's policy imposed a delay. Absent: it took effect at `at`. Until this instant the record confers nothing and is not published, and any administrator who may revoke it may do so.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"justification\": {\n \"description\": \"The actor's statement of why nobody else could grant this right. Shown to every community administrator, every namespace admin of the namespace and every owner of the resource; kept in the audit record; never published.\",\n \"maxLength\": 2048,\n \"minLength\": 1,\n \"pattern\": \"\\\\S\",\n \"type\": \"string\"\n },\n \"ratifiedAt\": {\n \"description\": \"When it was ratified. Present exactly when `ratifiedBy` is.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"ratifiedBy\": {\n \"$ref\": \"#/$defs/Did\",\n \"description\": \"The administrator who ratified the record — never its subject. Absent while unratified.\"\n }\n },\n \"required\": [\n \"by\",\n \"at\",\n \"justification\"\n ],\n \"title\": \"BreakGlass\",\n \"type\": \"object\"\n },\n \"Did\": {\n \"description\": \"A bare DID in the W3C DID Core syntax (§3.1): `did:`, a method name of lowercase letters and digits, `:`, and a method-specific id of colon-separated segments drawn from `A-Z a-z 0-9 . - _` and percent-encoded octets, the last segment non-empty. A DID URL is not a DID: no path, query or fragment (`/`, `?`, `#`), so a verification-method id such as `did:key:z6Mk…#z6Mk…` is refused. Compared by exact string equality — no case folding or percent-decoding. A consumer MUST still treat the value as data: the pattern keeps shell metacharacters, whitespace and quotes out of the wire form, but it does not make a DID safe to splice into a command or markup.\",\n \"maxLength\": 2048,\n \"pattern\": \"^did:[a-z0-9]+:(?:(?:[A-Za-z0-9._-]|%[0-9A-Fa-f]{2})*:)*(?:[A-Za-z0-9._-]|%[0-9A-Fa-f]{2})+$\",\n \"title\": \"Did\",\n \"type\": \"string\"\n },\n \"DriftItem\": {\n \"additionalProperties\": false,\n \"description\": \"One difference between the forge's observed state and the VTC's projection of a repository.\",\n \"properties\": {\n \"account\": {\n \"$ref\": \"#/$defs/ForgeAccount\",\n \"description\": \"Whose role differs, for the three role types.\"\n },\n \"expected\": {\n \"description\": \"What the projection calls for, in the forge's own vocabulary. Absent when the projection calls for nothing.\",\n \"maxLength\": 256,\n \"type\": \"string\"\n },\n \"observed\": {\n \"description\": \"What the forge shows, in the forge's own vocabulary (a role name such as `maintain`, a setting name). Absent when nothing is there.\",\n \"maxLength\": 256,\n \"type\": \"string\"\n },\n \"resource\": {\n \"$ref\": \"#/$defs/RepoResource\"\n },\n \"type\": {\n \"description\": \"`roleAdded` — someone holds a forge role the projection does not give them. `roleRemoved` — a projected role is missing. `roleChanged` — a projected role is present at another level. `requiredCheckMissing` — the verify-trust check is no longer required. `protectionWeakened` — branch protection or a ruleset is weaker than the projection in another way (force-push allowed, bypass actors added). `bootstrapMissing` — a bootstrap file or variable is gone.\",\n \"enum\": [\n \"roleAdded\",\n \"roleRemoved\",\n \"roleChanged\",\n \"requiredCheckMissing\",\n \"protectionWeakened\",\n \"bootstrapMissing\"\n ],\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"type\",\n \"resource\"\n ],\n \"title\": \"DriftItem\",\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 \"ForgeAccount\": {\n \"additionalProperties\": false,\n \"description\": \"A person's account on one forge. `id` is authoritative; `login` is for display only, because logins can be renamed and re-registered.\",\n \"properties\": {\n \"forge\": {\n \"$ref\": \"#/$defs/ForgeHost\"\n },\n \"id\": {\n \"$ref\": \"#/$defs/ForgeId\"\n },\n \"login\": {\n \"description\": \"The account's current login, as the forge reported it when last seen. Display only.\",\n \"maxLength\": 100,\n \"minLength\": 1,\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"forge\",\n \"id\",\n \"login\"\n ],\n \"title\": \"ForgeAccount\",\n \"type\": \"object\"\n },\n \"ForgeHost\": {\n \"description\": \"The lowercased DNS host of a forge: `github.com`, a GitHub Enterprise Server host, `codeberg.org`, or a self-hosted Forgejo instance such as `git.example.org`. No scheme, no port, no path. The host is a segment of every resource, so a right never crosses forges.\",\n \"maxLength\": 253,\n \"minLength\": 3,\n \"pattern\": \"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$\",\n \"title\": \"ForgeHost\",\n \"type\": \"string\"\n },\n \"ForgeId\": {\n \"description\": \"An identifier the forge itself assigns — a repository id, a user or organisation id — carried as a string so a forge whose ids are not numbers needs no new version. GitHub and Forgejo ids are decimal integers written as strings (`\\\"812736451\\\"`). Unlike a name, it survives renames and transfers, which is why rights and bindings are keyed by it.\",\n \"maxLength\": 64,\n \"minLength\": 1,\n \"title\": \"ForgeId\",\n \"type\": \"string\"\n },\n \"GitNamespace\": {\n \"additionalProperties\": false,\n \"description\": \"The VTC's binding to one owner on one forge.\",\n \"properties\": {\n \"forge\": {\n \"$ref\": \"#/$defs/ForgeHost\"\n },\n \"id\": {\n \"$ref\": \"#/$defs/NamespaceId\"\n },\n \"kind\": {\n \"description\": \"Whether the owner is an organisation or a personal account, as the forge reports it. Present once known: a bridge-mode namespace learns it when binding completes, and a manual-mode namespace MAY never learn it.\",\n \"enum\": [\n \"organization\",\n \"user\"\n ],\n \"type\": \"string\"\n },\n \"mode\": {\n \"description\": \"`bridge` — a bridge service acts on the forge for this namespace (creates repositories, projects roles, reports drift). `manual` — no automation; people with forge access carry out the steps the VTC names, and the VTC governs the rights alone.\",\n \"enum\": [\n \"bridge\",\n \"manual\"\n ],\n \"type\": \"string\"\n },\n \"owner\": {\n \"$ref\": \"#/$defs/Segment\",\n \"description\": \"The organisation or user on the forge, lowercased.\"\n },\n \"state\": {\n \"description\": \"`pending` — binding has started and the forge-side proof has not arrived yet. `bound` — the VTC governs rights under this namespace.\",\n \"enum\": [\n \"pending\",\n \"bound\"\n ],\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"id\",\n \"forge\",\n \"owner\",\n \"mode\",\n \"state\"\n ],\n \"title\": \"GitNamespace\",\n \"type\": \"object\"\n },\n \"LinkedAccount\": {\n \"additionalProperties\": false,\n \"description\": \"A forge account linked to the caller's DID with git-ns/account/link, and when the link completed.\",\n \"properties\": {\n \"account\": {\n \"$ref\": \"#/$defs/ForgeAccount\",\n \"description\": \"The linked account. `id` is authoritative; `login` is as the forge last reported it.\"\n },\n \"linkedAt\": {\n \"description\": \"When the link completed: when the VTC recorded the account against the caller's DID.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"account\",\n \"linkedAt\"\n ],\n \"title\": \"LinkedAccount\",\n \"type\": \"object\"\n },\n \"NamespaceId\": {\n \"description\": \"The VTC's opaque identifier for a namespace, assigned when it is bound. Stable for the life of the binding; never reused for another binding.\",\n \"maxLength\": 128,\n \"minLength\": 1,\n \"title\": \"NamespaceId\",\n \"type\": \"string\"\n },\n \"RepoResource\": {\n \"description\": \"A forge-qualified resource naming exactly one repository: `<forge-host>/<owner>/<repo>`, lowercase.\",\n \"maxLength\": 455,\n \"pattern\": \"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+/[a-z0-9_-][a-z0-9._-]{0,99}/[a-z0-9_-][a-z0-9._-]{0,99}$\",\n \"title\": \"RepoResource\",\n \"type\": \"string\"\n },\n \"RepoSummary\": {\n \"additionalProperties\": false,\n \"description\": \"One repository as the VTC records it.\",\n \"properties\": {\n \"bootstrap\": {\n \"$ref\": \"#/$defs/Bootstrap\"\n },\n \"forgeId\": {\n \"$ref\": \"#/$defs/ForgeId\",\n \"description\": \"The forge's repository id. Absent until the forge has confirmed the repository exists (a `pendingCreate` repository, or one adopted in bridge mode before the first inspection).\"\n },\n \"owners\": {\n \"description\": \"The DIDs holding `git.repo.own` on this repository by an explicit grant. Empty only for an `unmanaged` repository, and for an `orphaned` one whose ownership rests with the namespace admins by implication.\",\n \"items\": {\n \"$ref\": \"#/$defs/Did\"\n },\n \"type\": \"array\",\n \"uniqueItems\": true\n },\n \"resource\": {\n \"$ref\": \"#/$defs/RepoResource\"\n },\n \"state\": {\n \"description\": \"`pendingCreate` — the name is reserved and the repository is not yet confirmed on the forge. `active` — managed. `archived` — archived through git-ns/repo/archive; commit rights on it are revoked. `detached` — no longer governed: its namespace was unbound, or it moved outside the namespace. `orphaned` — its last owner left the community and ownership passed to the namespace admins, who have not yet named a new owner. `unmanaged` — it exists on the forge inside a bound namespace but was never created or adopted through the VTC.\",\n \"enum\": [\n \"pendingCreate\",\n \"active\",\n \"archived\",\n \"detached\",\n \"orphaned\",\n \"unmanaged\"\n ],\n \"type\": \"string\"\n },\n \"sync\": {\n \"$ref\": \"#/$defs/Sync\"\n },\n \"visibility\": {\n \"$ref\": \"#/$defs/RepoVisibility\"\n }\n },\n \"required\": [\n \"resource\",\n \"visibility\",\n \"state\",\n \"owners\",\n \"bootstrap\",\n \"sync\"\n ],\n \"title\": \"RepoSummary\",\n \"type\": \"object\"\n },\n \"RepoVisibility\": {\n \"description\": \"Repository visibility on the forge.\",\n \"enum\": [\n \"public\",\n \"private\"\n ],\n \"title\": \"RepoVisibility\",\n \"type\": \"string\"\n },\n \"Resource\": {\n \"description\": \"A forge-qualified resource: `<forge-host>/<owner>` for a namespace, or `<forge-host>/<owner>/<repo>` for one repository, all lowercase — `github.com/acme`, `github.com/acme/widgets`, `codeberg.org/acme`. The forge is never implied: `acme/widgets` alone is not a resource. Containment is by whole segment: `github.com/acme` contains `github.com/acme/widgets` and does not contain `github.com/acme-labs/x` or `codeberg.org/acme/widgets`.\",\n \"maxLength\": 455,\n \"pattern\": \"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+(?:/[a-z0-9_-][a-z0-9._-]{0,99}){1,2}$\",\n \"title\": \"Resource\",\n \"type\": \"string\"\n },\n \"Response\": {\n \"$anchor\": \"response\",\n \"additionalProperties\": false,\n \"description\": \"What the caller may see — or, with `scope: administrator`, everything in the namespaces they administer — and the caller's own linked forge accounts.\",\n \"properties\": {\n \"accounts\": {\n \"description\": \"The forge accounts linked to the caller's own DID — never another member's — at most one per forge. With `resource`, only the account on that resource's forge. Empty when the caller has linked none.\",\n \"items\": {\n \"$ref\": \"#/$defs/LinkedAccount\"\n },\n \"type\": \"array\"\n },\n \"ext\": {\n \"$ref\": \"#/$defs/Ext\"\n },\n \"namespaces\": {\n \"description\": \"Namespaces bound to this VTC that contain, or are contained by, `resource`. With `scope: administrator`, only those the caller administers. With `breakGlass: true`, only those containing a returned record.\",\n \"items\": {\n \"$ref\": \"#/$defs/GitNamespace\"\n },\n \"type\": \"array\"\n },\n \"repos\": {\n \"description\": \"Repositories within `resource`. `unmanaged` repositories are included only for callers holding `git.ns.admin` over them, or with `scope: administrator`. With `breakGlass: true`, only those carrying a returned record.\",\n \"items\": {\n \"$ref\": \"#/$defs/RepoSummary\"\n },\n \"type\": \"array\"\n },\n \"rights\": {\n \"description\": \"Rights within `resource` the caller may see: always the caller's own; every right on a resource the caller owns or administers; every unratified break-glass record in a namespace they administer or on a resource they own. With `scope: administrator`, every recorded right in the namespaces the caller administers. `reason` is omitted except on resources the caller owns or administers. With `breakGlass: true`, only records carrying `breakGlass`.\",\n \"items\": {\n \"$ref\": \"#/$defs/RightRecord\"\n },\n \"type\": \"array\"\n }\n },\n \"required\": [\n \"namespaces\",\n \"repos\",\n \"rights\",\n \"accounts\"\n ],\n \"title\": \"Git Namespaces — View — response payload\",\n \"type\": \"object\"\n },\n \"Right\": {\n \"description\": \"One of the five git rights. Each string is also the TRQP `action` the VTC publishes the right under in its Trust Registry, so it is carried verbatim. `git.ns.admin` and `git.repo.create` apply to a namespace resource; `git.repo.own` and `git.repo.maintain` to a repository resource; `git.commit.sign` to either.\",\n \"enum\": [\n \"git.ns.admin\",\n \"git.repo.create\",\n \"git.repo.own\",\n \"git.repo.maintain\",\n \"git.commit.sign\"\n ],\n \"title\": \"Right\",\n \"type\": \"string\"\n },\n \"RightRecord\": {\n \"additionalProperties\": false,\n \"description\": \"One recorded right. Implied rights (§4.2 of the rights model: `own` implies `maintain` implies `commit.sign` on the same resource; `ns.admin` implies `repo.create` and `own` across its namespace) are not records and never appear as RightRecords. A record carrying `breakGlass` was given by its subject to themselves through git-ns/right/break-glass; it is a real right, published like any other, and is shown with that flag on every surface that shows the record.\",\n \"properties\": {\n \"breakGlass\": {\n \"$ref\": \"#/$defs/BreakGlass\",\n \"description\": \"Present exactly when the subject gave themselves this right through git-ns/right/break-glass. Absent for every other record.\"\n },\n \"expiresAt\": {\n \"description\": \"When the right lapses. Absent: no expiry.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"grantedAt\": {\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"grantedBy\": {\n \"$ref\": \"#/$defs/Did\",\n \"description\": \"The actor whose task caused the right: the granter, the creator of a repository (for its first `own`), the adopting admin, the transferring owner, or the binding admin (for the first `git.ns.admin`). The VTC's own DID for a right it derives from its configuration.\"\n },\n \"reason\": {\n \"description\": \"The granter's free-text reason. Disclosed only to holders of `git.repo.own` on the resource and of `git.ns.admin` over it.\",\n \"maxLength\": 1024,\n \"type\": \"string\"\n },\n \"resource\": {\n \"$ref\": \"#/$defs/Resource\"\n },\n \"right\": {\n \"$ref\": \"#/$defs/Right\"\n },\n \"subject\": {\n \"$ref\": \"#/$defs/Did\",\n \"description\": \"Who holds the right. For `git.commit.sign` this is the DID whose commit signatures the CI check accepts.\"\n }\n },\n \"required\": [\n \"subject\",\n \"right\",\n \"resource\",\n \"grantedBy\",\n \"grantedAt\"\n ],\n \"title\": \"RightRecord\",\n \"type\": \"object\"\n },\n \"Segment\": {\n \"description\": \"One lowercased owner or repository name. Forges compare these case-insensitively, so the wire form is always lowercase and a producer lowercases before sending. A leading `.` is refused, which rules out `.` and `..`.\",\n \"maxLength\": 100,\n \"minLength\": 1,\n \"pattern\": \"^[a-z0-9_-][a-z0-9._-]*$\",\n \"title\": \"Segment\",\n \"type\": \"string\"\n },\n \"Sync\": {\n \"additionalProperties\": false,\n \"description\": \"How the forge compares with the VTC's projection for one repository.\",\n \"properties\": {\n \"checkedAt\": {\n \"description\": \"When the forge was last compared. Absent if never.\",\n \"format\": \"date-time\",\n \"type\": \"string\"\n },\n \"drift\": {\n \"description\": \"Outstanding drift. Empty unless `state` is `drift`.\",\n \"items\": {\n \"$ref\": \"#/$defs/DriftItem\"\n },\n \"type\": \"array\"\n },\n \"state\": {\n \"description\": \"`inSync` — the last comparison found no drift. `drift` — it found some, listed in `drift`. `pending` — a change has been sent to the forge and not yet confirmed. `unchecked` — nothing compares this repository (a manual-mode namespace).\",\n \"enum\": [\n \"inSync\",\n \"drift\",\n \"pending\",\n \"unchecked\"\n ],\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"state\",\n \"drift\"\n ],\n \"title\": \"Sync\",\n \"type\": \"object\"\n }\n },\n \"$ref\": \"#/$defs/Response\",\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\n}\n",
);
}
impl crate::RequestPayload for Payload {
type Response = Response;
}
/// The extended error codes this specification declares (SPEC §7.3 item 9,
/// §8.5), in declaration order. Empty when it declares none.
pub const ERROR_CODES: &[crate::DeclaredErrorCode] = &[error_codes::NOT_ADMINISTRATOR];
/// One constant per extended error code this specification declares
/// (SPEC §7.3 item 9), named for its local part.
///
/// Emit these rather than a string literal: the code is read from the
/// specification, so it cannot name a code the specification never
/// declared.
pub mod error_codes {
/// `git-ns/view:notAdministrator`
///
/// `scope: administrator` was asked for, and the caller administers no namespace within `resource` — they hold neither the community-administrator capability nor a live `git.ns.admin` on such a namespace. Returned identically for a resource that names no namespace this VTC has, so the code cannot be used to learn which namespaces exist.
///
/// Declared `retryable: false`.
pub const NOT_ADMINISTRATOR: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "git-ns/view:notAdministrator",
retryable: false,
};
}
#[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).
#[test]
fn request_example_1() {
const JSON: &str = "{\n \"id\": \"urn:uuid:4c1f0e52-9d7b-4a0e-8f15-2b6f0d1c7a01\",\n \"type\": \"https://trusttasks.org/spec/git-ns/view/0.5\",\n \"threadId\": \"urn:uuid:4c1f0e52-9d7b-4a0e-8f15-2b6f0d1c7a01\",\n \"issuer\": \"did:webvh:QmBobScid2:acme-vtc.example:bob\",\n \"recipient\": \"did:webvh:QmVtcScid7:acme-vtc.example\",\n \"issuedAt\": \"2026-09-24T08:00:00Z\",\n \"payload\": {\n \"resource\": \"github.com/acme\"\n }\n}\n";
let doc: crate::TrustTask<super::Payload> =
serde_json::from_str(JSON).expect("deserialize request example");
let rendered = serde_json::to_value(&doc).expect("re-serialize");
let expected: serde_json::Value = serde_json::from_str(JSON).expect("re-parse expected");
assert_eq!(rendered, expected, "request example failed round-trip");
}
#[test]
fn request_example_2() {
const JSON: &str = "{\n \"id\": \"urn:uuid:4c1f0e52-9d7b-4a0e-8f15-2b6f0d1c7a11\",\n \"type\": \"https://trusttasks.org/spec/git-ns/view/0.5\",\n \"threadId\": \"urn:uuid:4c1f0e52-9d7b-4a0e-8f15-2b6f0d1c7a11\",\n \"issuer\": \"did:webvh:QmDanaScid8:acme-vtc.example:dana\",\n \"recipient\": \"did:webvh:QmVtcScid7:acme-vtc.example\",\n \"issuedAt\": \"2026-09-26T08:00:00Z\",\n \"payload\": {\n \"scope\": \"administrator\",\n \"breakGlass\": true\n }\n}\n";
let doc: crate::TrustTask<super::Payload> =
serde_json::from_str(JSON).expect("deserialize request example");
let rendered = serde_json::to_value(&doc).expect("re-serialize");
let expected: serde_json::Value = serde_json::from_str(JSON).expect("re-parse expected");
assert_eq!(rendered, expected, "request example failed round-trip");
}
#[test]
fn response_example_1() {
const JSON: &str = "{\n \"id\": \"urn:uuid:4c1f0e52-9d7b-4a0e-8f15-2b6f0d1c7a02\",\n \"type\": \"https://trusttasks.org/spec/git-ns/view/0.5#response\",\n \"threadId\": \"urn:uuid:4c1f0e52-9d7b-4a0e-8f15-2b6f0d1c7a01\",\n \"issuer\": \"did:webvh:QmVtcScid7:acme-vtc.example\",\n \"recipient\": \"did:webvh:QmBobScid2:acme-vtc.example:bob\",\n \"issuedAt\": \"2026-09-24T08:00:01Z\",\n \"payload\": {\n \"namespaces\": [\n {\n \"id\": \"ns_01J8Z6Q4M2\",\n \"forge\": \"github.com\",\n \"owner\": \"acme\",\n \"kind\": \"organization\",\n \"mode\": \"bridge\",\n \"state\": \"bound\"\n }\n ],\n \"repos\": [\n {\n \"resource\": \"github.com/acme/widgets\",\n \"forgeId\": \"812736451\",\n \"visibility\": \"public\",\n \"state\": \"active\",\n \"owners\": [\n \"did:webvh:QmAliceScid1:acme-vtc.example:alice\",\n \"did:webvh:QmCarolScid3:acme-vtc.example:carol\"\n ],\n \"bootstrap\": {\n \"workflow\": true,\n \"keyring\": true,\n \"variables\": true,\n \"requiredCheck\": true\n },\n \"sync\": {\n \"state\": \"drift\",\n \"checkedAt\": \"2026-09-23T09:58:00Z\",\n \"drift\": [\n {\n \"type\": \"roleAdded\",\n \"resource\": \"github.com/acme/widgets\",\n \"account\": {\n \"forge\": \"github.com\",\n \"id\": \"5550123\",\n \"login\": \"eve-dev\"\n },\n \"observed\": \"write\"\n }\n ]\n }\n },\n {\n \"resource\": \"github.com/acme/gadgets\",\n \"forgeId\": \"812736990\",\n \"visibility\": \"public\",\n \"state\": \"active\",\n \"owners\": [\n \"did:webvh:QmBobScid2:acme-vtc.example:bob\"\n ],\n \"bootstrap\": {\n \"workflow\": true,\n \"keyring\": true,\n \"variables\": true,\n \"requiredCheck\": true\n },\n \"sync\": {\n \"state\": \"inSync\",\n \"checkedAt\": \"2026-09-23T09:58:00Z\",\n \"drift\": []\n }\n }\n ],\n \"rights\": [\n {\n \"subject\": \"did:webvh:QmBobScid2:acme-vtc.example:bob\",\n \"right\": \"git.repo.create\",\n \"resource\": \"github.com/acme\",\n \"grantedBy\": \"did:webvh:QmAliceScid1:acme-vtc.example:alice\",\n \"grantedAt\": \"2026-09-23T10:00:01Z\"\n },\n {\n \"subject\": \"did:webvh:QmBobScid2:acme-vtc.example:bob\",\n \"right\": \"git.repo.own\",\n \"resource\": \"github.com/acme/gadgets\",\n \"grantedBy\": \"did:webvh:QmBobScid2:acme-vtc.example:bob\",\n \"grantedAt\": \"2026-09-23T10:05:00Z\"\n },\n {\n \"subject\": \"did:webvh:QmDanScid4:dan.example\",\n \"right\": \"git.commit.sign\",\n \"resource\": \"github.com/acme/gadgets\",\n \"grantedBy\": \"did:webvh:QmBobScid2:acme-vtc.example:bob\",\n \"grantedAt\": \"2026-09-23T11:00:01Z\",\n \"expiresAt\": \"2026-12-22T00:00:00Z\",\n \"reason\": \"External contributor for the 1.0 push\"\n }\n ],\n \"accounts\": [\n {\n \"account\": {\n \"forge\": \"github.com\",\n \"id\": \"9120045\",\n \"login\": \"bob-builds\"\n },\n \"linkedAt\": \"2026-09-23T10:02:14Z\"\n }\n ]\n }\n}\n";
let doc: crate::TrustTask<super::Response> =
serde_json::from_str(JSON).expect("deserialize response example");
let rendered = serde_json::to_value(&doc).expect("re-serialize");
let expected: serde_json::Value = serde_json::from_str(JSON).expect("re-parse expected");
assert_eq!(rendered, expected, "response example failed round-trip");
}
#[test]
fn response_example_2() {
const JSON: &str = "{\n \"id\": \"urn:uuid:4c1f0e52-9d7b-4a0e-8f15-2b6f0d1c7a12\",\n \"type\": \"https://trusttasks.org/spec/git-ns/view/0.5#response\",\n \"threadId\": \"urn:uuid:4c1f0e52-9d7b-4a0e-8f15-2b6f0d1c7a11\",\n \"issuer\": \"did:webvh:QmVtcScid7:acme-vtc.example\",\n \"recipient\": \"did:webvh:QmDanaScid8:acme-vtc.example:dana\",\n \"issuedAt\": \"2026-09-26T08:00:01Z\",\n \"payload\": {\n \"namespaces\": [\n {\n \"id\": \"ns_01J8Z6Q4M2\",\n \"forge\": \"github.com\",\n \"owner\": \"acme\",\n \"kind\": \"organization\",\n \"mode\": \"bridge\",\n \"state\": \"bound\"\n }\n ],\n \"repos\": [],\n \"rights\": [\n {\n \"subject\": \"did:webvh:QmBobScid2:acme-vtc.example:bob\",\n \"right\": \"git.ns.admin\",\n \"resource\": \"github.com/acme\",\n \"grantedBy\": \"did:webvh:QmBobScid2:acme-vtc.example:bob\",\n \"grantedAt\": \"2026-09-25T22:14:03Z\",\n \"breakGlass\": {\n \"by\": \"did:webvh:QmBobScid2:acme-vtc.example:bob\",\n \"at\": \"2026-09-25T22:14:03Z\",\n \"justification\": \"Release 2.4 must ship tonight and Carol, our only admin, is on a flight until Monday.\"\n }\n }\n ],\n \"accounts\": []\n }\n}\n";
let doc: crate::TrustTask<super::Response> =
serde_json::from_str(JSON).expect("deserialize response example");
let rendered = serde_json::to_value(&doc).expect("re-serialize");
let expected: serde_json::Value = serde_json::from_str(JSON).expect("re-parse expected");
assert_eq!(rendered, expected, "response example failed round-trip");
}
/// 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)] = &[
("`resource` names its forge.", "{\n \"resource\": \"acme\"\n}"),
("`resource` is lowercase.", "{\n \"resource\": \"github.com/ACME\"\n}"),
(
"Unknown members are refused: there is no subject filter, a member sees what they may see.",
"{\n \"subject\": \"did:webvh:QmDanScid4:dan.example\"\n}",
),
(
"`accounts` is a response member. A request cannot name whose accounts to return: the answer only ever carries the caller's own.",
"{\n \"accounts\": [\n {\n \"account\": {\n \"forge\": \"github.com\",\n \"id\": \"5550123\",\n \"login\": \"eve-dev\"\n },\n \"linkedAt\": \"2026-09-23T10:00:00Z\"\n }\n ]\n}",
),
(
"`scope` is `member` or `administrator`: there is no scope that widens the answer beyond what the caller administers.",
"{\n \"scope\": \"everything\"\n}",
),
(
"`breakGlass` is a boolean narrowing, not a filter on who broke the glass.",
"{\n \"breakGlass\": \"did:webvh:QmBobScid2:acme-vtc.example:bob\"\n}",
),
(
"An administrator's read still carries no subject: it answers for the namespaces the caller administers, never for a DID the request names.",
"{\n \"scope\": \"administrator\",\n \"subject\": \"did:webvh:QmBobScid2:acme-vtc.example:bob\"\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
);
}
}
}