//! Generated by `trust-tasks-codegen` — do not edit by hand.
//!
//! Spec slug: `git-ns/bridge/job`. Version: `0.2`.
#![allow(deprecated)]
/// Why this specification version is deprecated (SPEC "Superseded and
/// Withdrawn Versions"), or `None` while it is current.
pub const DEPRECATION: Option<&str> = Some("superseded by git-ns/bridge/job/0.6");
#[allow(unused_imports)]
use serde::{Deserialize, Serialize};
/// Error types.
pub mod error {
/// Error from a `TryFrom` or `FromStr` implementation.
pub struct ConversionError(::std::borrow::Cow<'static, str>);
impl ::std::error::Error for ConversionError {}
impl ::std::fmt::Display for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Display::fmt(&self.0, f)
}
}
impl ::std::fmt::Debug for ConversionError {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> Result<(), ::std::fmt::Error> {
::std::fmt::Debug::fmt(&self.0, f)
}
}
impl From<&'static str> for ConversionError {
fn from(value: &'static str) -> Self {
Self(value.into())
}
}
impl From<String> for ConversionError {
fn from(value: String) -> Self {
Self(value.into())
}
}
}
///The forge owner whose control the binding admin is to prove.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct BindTarget {
pub forge: ForgeHost,
pub owner: Segment,
}
impl BindTarget {
pub fn builder() -> builder::BindTarget {
Default::default()
}
}
///`DesiredRole`
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct DesiredRole {
///The subject's linked account on this namespace's forge.
pub account: ForgeAccount,
///The subject's highest effective right on the target, which the forge adapter maps to one of its roles.
pub right: Right,
pub subject: Did,
}
impl DesiredRole {
pub fn builder() -> builder::DesiredRole {
Default::default()
}
}
///A DID, compared by exact string equality.
///
#[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]+:\\S+$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^did:[a-z0-9]+:\\S+$\"".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())
})
}
}
///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.
///
#[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`
///
#[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.
///
#[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.
///
#[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.
///
#[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.
///
#[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 identifier for a job, unique across the VTC's jobs.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct JobId(::std::string::String);
impl ::std::ops::Deref for JobId {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<JobId> for ::std::string::String {
fn from(value: JobId) -> Self {
value.0
}
}
impl ::std::str::FromStr for JobId {
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 JobId {
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 JobId {
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 JobId {
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 JobId {
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 opaque identifier for a namespace, assigned when it is bound. Stable for the life of the binding; never reused for another binding.
///
#[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())
})
}
}
///The VTC asks its bridge to do one piece of forge work in a namespace. The job names what to do (`kind`) and carries the desired state, never forge credentials — the bridge holds those. Which optional members a job carries is fixed by its `kind` (see the specification's kind table); a bridge refuses a job that carries a member its kind does not use, or lacks one its kind requires.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
#[deprecated(note = "superseded by git-ns/bridge/job/0.6")]
pub struct Payload {
///The complete set of people who should hold a forge role on the target. The bridge converges to exactly this set among the roles it manages: it adds or changes roles to match and removes managed roles not listed. `projectRoles` and `createRepo` only.
#[serde(
rename = "desiredRoles",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub desired_roles: ::std::option::Option<Vec<DesiredRole>>,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
///The VTC's identifier for this job. The bridge reports on it with git-ns/bridge/result.
#[serde(rename = "jobId")]
pub job_id: JobId,
///What to do. `projectRoles` — converge forge roles to `desiredRoles`, and remove whatever role each of `removeAccounts` holds on `repo`. `createRepo` — create `repo`, run the bootstrap plan, and project `desiredRoles`. `bootstrap` — run the bootstrap plan, or the listed `steps` of it, on an existing `repo`. `archive` — archive `repo`. `inspect` — compare the forge with the projection for `repo`, or for the whole namespace. `beginBind` — start the proof that the binding admin controls `target`. `beginAccountLink` — start linking `subject`'s account on this namespace's forge.
pub kind: PayloadKind,
///The namespace the job acts in. It also selects the bridge's forge credentials for it.
pub namespace: NamespaceId,
///Accounts whose direct role on `repo` the bridge removes, whatever that role is — including a role the bridge does not manage and would otherwise only report as drift. Matched by `forge` and `id`; `login` is display only. No account listed here may also appear in `desiredRoles`. `projectRoles` with `repo` only.
#[serde(
rename = "removeAccounts",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub remove_accounts: ::std::option::Option<Vec<ForgeAccount>>,
///The repository. Required for `createRepo`, `bootstrap` and `archive`. For `projectRoles`, absent means the namespace-level roles (organisation owners), where only `git.ns.admin` is projected. For `inspect`, absent means a sweep of every repository in the namespace.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub repo: ::std::option::Option<RepoResource>,
///How to create the repository. `createRepo` only.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub spec: ::std::option::Option<RepoSpec>,
///Run only these steps of the adapter's bootstrap plan, in the plan's order. Absent: the whole plan. `bootstrap` only.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub steps: ::std::option::Option<Vec<StepName>>,
///The member whose forge account is being linked. `beginAccountLink` only.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub subject: ::std::option::Option<Did>,
///`beginBind` only.
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub target: ::std::option::Option<BindTarget>,
}
impl Payload {
pub fn builder() -> builder::Payload {
Default::default()
}
}
///What to do. `projectRoles` — converge forge roles to `desiredRoles`, and remove whatever role each of `removeAccounts` holds on `repo`. `createRepo` — create `repo`, run the bootstrap plan, and project `desiredRoles`. `bootstrap` — run the bootstrap plan, or the listed `steps` of it, on an existing `repo`. `archive` — archive `repo`. `inspect` — compare the forge with the projection for `repo`, or for the whole namespace. `beginBind` — start the proof that the binding admin controls `target`. `beginAccountLink` — start linking `subject`'s account on this namespace's forge.
///
#[derive(
::serde::Deserialize,
::serde::Serialize,
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
)]
#[non_exhaustive]
pub enum PayloadKind {
#[serde(rename = "projectRoles")]
ProjectRoles,
#[serde(rename = "createRepo")]
CreateRepo,
#[serde(rename = "bootstrap")]
Bootstrap,
#[serde(rename = "archive")]
Archive,
#[serde(rename = "inspect")]
Inspect,
#[serde(rename = "beginBind")]
BeginBind,
#[serde(rename = "beginAccountLink")]
BeginAccountLink,
}
impl ::std::fmt::Display for PayloadKind {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
match *self {
Self::ProjectRoles => f.write_str("projectRoles"),
Self::CreateRepo => f.write_str("createRepo"),
Self::Bootstrap => f.write_str("bootstrap"),
Self::Archive => f.write_str("archive"),
Self::Inspect => f.write_str("inspect"),
Self::BeginBind => f.write_str("beginBind"),
Self::BeginAccountLink => f.write_str("beginAccountLink"),
}
}
}
impl ::std::str::FromStr for PayloadKind {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
match value {
"projectRoles" => Ok(Self::ProjectRoles),
"createRepo" => Ok(Self::CreateRepo),
"bootstrap" => Ok(Self::Bootstrap),
"archive" => Ok(Self::Archive),
"inspect" => Ok(Self::Inspect),
"beginBind" => Ok(Self::BeginBind),
"beginAccountLink" => Ok(Self::BeginAccountLink),
_ => Err("invalid value".into()),
}
}
}
impl ::std::convert::TryFrom<&str> for PayloadKind {
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 PayloadKind {
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 PayloadKind {
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.
///
#[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())
})
}
}
///`RepoSpec`
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct RepoSpec {
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub description: ::std::option::Option<RepoSpecDescription>,
pub visibility: RepoVisibility,
}
impl RepoSpec {
pub fn builder() -> builder::RepoSpec {
Default::default()
}
}
///`RepoSpecDescription`
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct RepoSpecDescription(::std::string::String);
impl ::std::ops::Deref for RepoSpecDescription {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<RepoSpecDescription> for ::std::string::String {
fn from(value: RepoSpecDescription) -> Self {
value.0
}
}
impl ::std::str::FromStr for RepoSpecDescription {
type Err = self::error::ConversionError;
fn from_str(value: &str) -> ::std::result::Result<Self, self::error::ConversionError> {
if value.chars().count() > 350usize {
return Err("longer than 350 characters".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for RepoSpecDescription {
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 RepoSpecDescription {
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 RepoSpecDescription {
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 RepoSpecDescription {
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())
})
}
}
///Repository visibility on the forge.
///
#[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()
}
}
///Whether the bridge took the job.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
#[deprecated(note = "superseded by git-ns/bridge/job/0.6")]
pub struct Response {
///`true` — the job is durably queued, or was already queued or running under this `jobId`; a git-ns/bridge/result follows. `false` — the bridge already finished this `jobId`; it does not run it again, and sends its git-ns/bridge/result again.
pub accepted: bool,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub ext: ::std::option::Option<Ext>,
#[serde(rename = "jobId")]
pub job_id: JobId,
#[serde(default, skip_serializing_if = "::std::option::Option::is_none")]
pub next: ::std::option::Option<ResponseNext>,
}
impl Response {
pub fn builder() -> builder::Response {
Default::default()
}
}
///For `beginBind` and `beginAccountLink` when `accepted` is `true`: where the VTC sends the person.
///
#[derive(::serde::Deserialize, ::serde::Serialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct ResponseNext {
#[serde(rename = "expiresAt")]
pub expires_at: ::chrono::DateTime<::chrono::offset::Utc>,
pub url: ::std::string::String,
///The device-flow code, for a forge that uses one.
#[serde(
rename = "userCode",
default,
skip_serializing_if = "::std::option::Option::is_none"
)]
pub user_code: ::std::option::Option<ResponseNextUserCode>,
}
impl ResponseNext {
pub fn builder() -> builder::ResponseNext {
Default::default()
}
}
///The device-flow code, for a forge that uses one.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct ResponseNextUserCode(::std::string::String);
impl ::std::ops::Deref for ResponseNextUserCode {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<ResponseNextUserCode> for ::std::string::String {
fn from(value: ResponseNextUserCode) -> Self {
value.0
}
}
impl ::std::str::FromStr for ResponseNextUserCode {
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 ResponseNextUserCode {
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 ResponseNextUserCode {
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 ResponseNextUserCode {
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 ResponseNextUserCode {
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 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.
///
#[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 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 `..`.
///
#[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())
})
}
}
///One step of a forge adapter's plan. Forge-neutral names: `create`, `workflow`, `keyring`, `variables`, `requiredCheck`, `roles`, `archive`. An adapter MAY add its own (`mergeStyle`, `runner`), which a VTC displays but need not understand.
///
#[derive(::serde::Serialize, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[serde(transparent)]
pub struct StepName(::std::string::String);
impl ::std::ops::Deref for StepName {
type Target = ::std::string::String;
fn deref(&self) -> &::std::string::String {
&self.0
}
}
impl ::std::convert::From<StepName> for ::std::string::String {
fn from(value: StepName) -> Self {
value.0
}
}
impl ::std::str::FromStr for StepName {
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());
}
static PATTERN: ::std::sync::LazyLock<::regress::Regex> =
::std::sync::LazyLock::new(|| ::regress::Regex::new("^[a-z][A-Za-z0-9]*$").unwrap());
if PATTERN.find(value).is_none() {
return Err("doesn't match pattern \"^[a-z][A-Za-z0-9]*$\"".into());
}
Ok(Self(value.to_string()))
}
}
impl ::std::convert::TryFrom<&str> for StepName {
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 StepName {
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 StepName {
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 StepName {
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())
})
}
}
/// Types for composing complex structures.
pub mod builder {
#[derive(Clone, Debug)]
pub struct BindTarget {
forge: ::std::result::Result<super::ForgeHost, ::std::string::String>,
owner: ::std::result::Result<super::Segment, ::std::string::String>,
}
impl ::std::default::Default for BindTarget {
fn default() -> Self {
Self {
forge: Err("no value supplied for forge".to_string()),
owner: Err("no value supplied for owner".to_string()),
}
}
}
impl BindTarget {
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 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
}
}
impl ::std::convert::TryFrom<BindTarget> for super::BindTarget {
type Error = super::error::ConversionError;
fn try_from(
value: BindTarget,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
forge: value.forge?,
owner: value.owner?,
})
}
}
impl ::std::convert::From<super::BindTarget> for BindTarget {
fn from(value: super::BindTarget) -> Self {
Self {
forge: Ok(value.forge),
owner: Ok(value.owner),
}
}
}
#[derive(Clone, Debug)]
pub struct DesiredRole {
account: ::std::result::Result<super::ForgeAccount, ::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 DesiredRole {
fn default() -> Self {
Self {
account: Err("no value supplied for account".to_string()),
right: Err("no value supplied for right".to_string()),
subject: Err("no value supplied for subject".to_string()),
}
}
}
impl DesiredRole {
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 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<DesiredRole> for super::DesiredRole {
type Error = super::error::ConversionError;
fn try_from(
value: DesiredRole,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
account: value.account?,
right: value.right?,
subject: value.subject?,
})
}
}
impl ::std::convert::From<super::DesiredRole> for DesiredRole {
fn from(value: super::DesiredRole) -> Self {
Self {
account: Ok(value.account),
right: Ok(value.right),
subject: Ok(value.subject),
}
}
}
#[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 Payload {
desired_roles: ::std::result::Result<
::std::option::Option<Vec<super::DesiredRole>>,
::std::string::String,
>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
job_id: ::std::result::Result<super::JobId, ::std::string::String>,
kind: ::std::result::Result<super::PayloadKind, ::std::string::String>,
namespace: ::std::result::Result<super::NamespaceId, ::std::string::String>,
remove_accounts: ::std::result::Result<
::std::option::Option<Vec<super::ForgeAccount>>,
::std::string::String,
>,
repo: ::std::result::Result<
::std::option::Option<super::RepoResource>,
::std::string::String,
>,
spec: ::std::result::Result<::std::option::Option<super::RepoSpec>, ::std::string::String>,
steps: ::std::result::Result<
::std::option::Option<Vec<super::StepName>>,
::std::string::String,
>,
subject: ::std::result::Result<::std::option::Option<super::Did>, ::std::string::String>,
target:
::std::result::Result<::std::option::Option<super::BindTarget>, ::std::string::String>,
}
impl ::std::default::Default for Payload {
fn default() -> Self {
Self {
desired_roles: Ok(Default::default()),
ext: Ok(Default::default()),
job_id: Err("no value supplied for job_id".to_string()),
kind: Err("no value supplied for kind".to_string()),
namespace: Err("no value supplied for namespace".to_string()),
remove_accounts: Ok(Default::default()),
repo: Ok(Default::default()),
spec: Ok(Default::default()),
steps: Ok(Default::default()),
subject: Ok(Default::default()),
target: Ok(Default::default()),
}
}
}
impl Payload {
pub fn desired_roles<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<Vec<super::DesiredRole>>>,
T::Error: ::std::fmt::Display,
{
self.desired_roles = value
.try_into()
.map_err(|e| format!("error converting supplied value for desired_roles: {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 job_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::JobId>,
T::Error: ::std::fmt::Display,
{
self.job_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for job_id: {e}"));
self
}
pub fn kind<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::PayloadKind>,
T::Error: ::std::fmt::Display,
{
self.kind = value
.try_into()
.map_err(|e| format!("error converting supplied value for kind: {e}"));
self
}
pub fn namespace<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::NamespaceId>,
T::Error: ::std::fmt::Display,
{
self.namespace = value
.try_into()
.map_err(|e| format!("error converting supplied value for namespace: {e}"));
self
}
pub fn remove_accounts<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<Vec<super::ForgeAccount>>>,
T::Error: ::std::fmt::Display,
{
self.remove_accounts = value
.try_into()
.map_err(|e| format!("error converting supplied value for remove_accounts: {e}"));
self
}
pub fn repo<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::RepoResource>>,
T::Error: ::std::fmt::Display,
{
self.repo = value
.try_into()
.map_err(|e| format!("error converting supplied value for repo: {e}"));
self
}
pub fn spec<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::RepoSpec>>,
T::Error: ::std::fmt::Display,
{
self.spec = value
.try_into()
.map_err(|e| format!("error converting supplied value for spec: {e}"));
self
}
pub fn steps<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<Vec<super::StepName>>>,
T::Error: ::std::fmt::Display,
{
self.steps = value
.try_into()
.map_err(|e| format!("error converting supplied value for steps: {e}"));
self
}
pub fn subject<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::Did>>,
T::Error: ::std::fmt::Display,
{
self.subject = value
.try_into()
.map_err(|e| format!("error converting supplied value for subject: {e}"));
self
}
pub fn target<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::BindTarget>>,
T::Error: ::std::fmt::Display,
{
self.target = value
.try_into()
.map_err(|e| format!("error converting supplied value for target: {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 {
desired_roles: value.desired_roles?,
ext: value.ext?,
job_id: value.job_id?,
kind: value.kind?,
namespace: value.namespace?,
remove_accounts: value.remove_accounts?,
repo: value.repo?,
spec: value.spec?,
steps: value.steps?,
subject: value.subject?,
target: value.target?,
})
}
}
impl ::std::convert::From<super::Payload> for Payload {
fn from(value: super::Payload) -> Self {
Self {
desired_roles: Ok(value.desired_roles),
ext: Ok(value.ext),
job_id: Ok(value.job_id),
kind: Ok(value.kind),
namespace: Ok(value.namespace),
remove_accounts: Ok(value.remove_accounts),
repo: Ok(value.repo),
spec: Ok(value.spec),
steps: Ok(value.steps),
subject: Ok(value.subject),
target: Ok(value.target),
}
}
}
#[derive(Clone, Debug)]
pub struct RepoSpec {
description: ::std::result::Result<
::std::option::Option<super::RepoSpecDescription>,
::std::string::String,
>,
visibility: ::std::result::Result<super::RepoVisibility, ::std::string::String>,
}
impl ::std::default::Default for RepoSpec {
fn default() -> Self {
Self {
description: Ok(Default::default()),
visibility: Err("no value supplied for visibility".to_string()),
}
}
}
impl RepoSpec {
pub fn description<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::RepoSpecDescription>>,
T::Error: ::std::fmt::Display,
{
self.description = value
.try_into()
.map_err(|e| format!("error converting supplied value for description: {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<RepoSpec> for super::RepoSpec {
type Error = super::error::ConversionError;
fn try_from(value: RepoSpec) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
description: value.description?,
visibility: value.visibility?,
})
}
}
impl ::std::convert::From<super::RepoSpec> for RepoSpec {
fn from(value: super::RepoSpec) -> Self {
Self {
description: Ok(value.description),
visibility: Ok(value.visibility),
}
}
}
#[derive(Clone, Debug)]
pub struct Response {
accepted: ::std::result::Result<bool, ::std::string::String>,
ext: ::std::result::Result<::std::option::Option<super::Ext>, ::std::string::String>,
job_id: ::std::result::Result<super::JobId, ::std::string::String>,
next: ::std::result::Result<
::std::option::Option<super::ResponseNext>,
::std::string::String,
>,
}
impl ::std::default::Default for Response {
fn default() -> Self {
Self {
accepted: Err("no value supplied for accepted".to_string()),
ext: Ok(Default::default()),
job_id: Err("no value supplied for job_id".to_string()),
next: Ok(Default::default()),
}
}
}
impl Response {
pub fn accepted<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<bool>,
T::Error: ::std::fmt::Display,
{
self.accepted = value
.try_into()
.map_err(|e| format!("error converting supplied value for accepted: {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 job_id<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<super::JobId>,
T::Error: ::std::fmt::Display,
{
self.job_id = value
.try_into()
.map_err(|e| format!("error converting supplied value for job_id: {e}"));
self
}
pub fn next<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ResponseNext>>,
T::Error: ::std::fmt::Display,
{
self.next = value
.try_into()
.map_err(|e| format!("error converting supplied value for next: {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 {
accepted: value.accepted?,
ext: value.ext?,
job_id: value.job_id?,
next: value.next?,
})
}
}
impl ::std::convert::From<super::Response> for Response {
fn from(value: super::Response) -> Self {
Self {
accepted: Ok(value.accepted),
ext: Ok(value.ext),
job_id: Ok(value.job_id),
next: Ok(value.next),
}
}
}
#[derive(Clone, Debug)]
pub struct ResponseNext {
expires_at:
::std::result::Result<::chrono::DateTime<::chrono::offset::Utc>, ::std::string::String>,
url: ::std::result::Result<::std::string::String, ::std::string::String>,
user_code: ::std::result::Result<
::std::option::Option<super::ResponseNextUserCode>,
::std::string::String,
>,
}
impl ::std::default::Default for ResponseNext {
fn default() -> Self {
Self {
expires_at: Err("no value supplied for expires_at".to_string()),
url: Err("no value supplied for url".to_string()),
user_code: Ok(Default::default()),
}
}
}
impl ResponseNext {
pub fn expires_at<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::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 url<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::string::String>,
T::Error: ::std::fmt::Display,
{
self.url = value
.try_into()
.map_err(|e| format!("error converting supplied value for url: {e}"));
self
}
pub fn user_code<T>(mut self, value: T) -> Self
where
T: ::std::convert::TryInto<::std::option::Option<super::ResponseNextUserCode>>,
T::Error: ::std::fmt::Display,
{
self.user_code = value
.try_into()
.map_err(|e| format!("error converting supplied value for user_code: {e}"));
self
}
}
impl ::std::convert::TryFrom<ResponseNext> for super::ResponseNext {
type Error = super::error::ConversionError;
fn try_from(
value: ResponseNext,
) -> ::std::result::Result<Self, super::error::ConversionError> {
Ok(Self {
expires_at: value.expires_at?,
url: value.url?,
user_code: value.user_code?,
})
}
}
impl ::std::convert::From<super::ResponseNext> for ResponseNext {
fn from(value: super::ResponseNext) -> Self {
Self {
expires_at: Ok(value.expires_at),
url: Ok(value.url),
user_code: Ok(value.user_code),
}
}
}
}
impl crate::Payload for Payload {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/git-ns/bridge/job/0.2";
const IS_PROOF_REQUIRED: bool = true;
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\"$defs\":{\"BindTarget\":{\"additionalProperties\":false,\"description\":\"The forge owner whose control the binding admin is to prove.\",\"properties\":{\"forge\":{\"$ref\":\"#/$defs/ForgeHost\"},\"owner\":{\"$ref\":\"#/$defs/Segment\"}},\"required\":[\"forge\",\"owner\"],\"title\":\"BindTarget\",\"type\":\"object\"},\"DesiredRole\":{\"additionalProperties\":false,\"properties\":{\"account\":{\"$ref\":\"#/$defs/ForgeAccount\",\"description\":\"The subject's linked account on this namespace's forge.\"},\"right\":{\"$ref\":\"#/$defs/Right\",\"description\":\"The subject's highest effective right on the target, which the forge adapter maps to one of its roles.\"},\"subject\":{\"$ref\":\"#/$defs/Did\"}},\"required\":[\"subject\",\"account\",\"right\"],\"type\":\"object\"},\"Did\":{\"description\":\"A DID, compared by exact string equality.\",\"maxLength\":2048,\"pattern\":\"^did:[a-z0-9]+:\\\\S+$\",\"title\":\"Did\",\"type\":\"string\"},\"Ext\":{\"additionalProperties\":true,\"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.\",\"minProperties\":1,\"propertyNames\":{\"pattern\":\"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"},\"title\":\"Ext\",\"type\":\"object\"},\"ForgeAccount\":{\"additionalProperties\":false,\"description\":\"A person's account on one forge. `id` is authoritative; `login` is for display only, because logins can be renamed and re-registered.\",\"properties\":{\"forge\":{\"$ref\":\"#/$defs/ForgeHost\"},\"id\":{\"$ref\":\"#/$defs/ForgeId\"},\"login\":{\"description\":\"The account's current login, as the forge reported it when last seen. Display only.\",\"maxLength\":100,\"minLength\":1,\"type\":\"string\"}},\"required\":[\"forge\",\"id\",\"login\"],\"title\":\"ForgeAccount\",\"type\":\"object\"},\"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.\",\"maxLength\":253,\"minLength\":3,\"pattern\":\"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$\",\"title\":\"ForgeHost\",\"type\":\"string\"},\"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.\",\"maxLength\":64,\"minLength\":1,\"title\":\"ForgeId\",\"type\":\"string\"},\"JobId\":{\"description\":\"The VTC's identifier for a job, unique across the VTC's jobs.\",\"maxLength\":128,\"minLength\":1,\"type\":\"string\"},\"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.\",\"maxLength\":128,\"minLength\":1,\"title\":\"NamespaceId\",\"type\":\"string\"},\"RepoResource\":{\"description\":\"A forge-qualified resource naming exactly one repository: `<forge-host>/<owner>/<repo>`, lowercase.\",\"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}$\",\"title\":\"RepoResource\",\"type\":\"string\"},\"RepoSpec\":{\"additionalProperties\":false,\"properties\":{\"description\":{\"maxLength\":350,\"type\":\"string\"},\"visibility\":{\"$ref\":\"#/$defs/RepoVisibility\"}},\"required\":[\"visibility\"],\"type\":\"object\"},\"RepoVisibility\":{\"description\":\"Repository visibility on the forge.\",\"enum\":[\"public\",\"private\"],\"title\":\"RepoVisibility\",\"type\":\"string\"},\"Response\":{\"$anchor\":\"response\",\"additionalProperties\":false,\"description\":\"Whether the bridge took the job.\",\"properties\":{\"accepted\":{\"description\":\"`true` — the job is durably queued, or was already queued or running under this `jobId`; a git-ns/bridge/result follows. `false` — the bridge already finished this `jobId`; it does not run it again, and sends its git-ns/bridge/result again.\",\"type\":\"boolean\"},\"ext\":{\"$ref\":\"#/$defs/Ext\"},\"jobId\":{\"$ref\":\"#/$defs/JobId\"},\"next\":{\"additionalProperties\":false,\"description\":\"For `beginBind` and `beginAccountLink` when `accepted` is `true`: where the VTC sends the person.\",\"properties\":{\"expiresAt\":{\"format\":\"date-time\",\"type\":\"string\"},\"url\":{\"format\":\"uri\",\"maxLength\":2048,\"pattern\":\"^https://\",\"type\":\"string\"},\"userCode\":{\"description\":\"The device-flow code, for a forge that uses one.\",\"maxLength\":64,\"minLength\":1,\"type\":\"string\"}},\"required\":[\"url\",\"expiresAt\"],\"type\":\"object\"}},\"required\":[\"jobId\",\"accepted\"],\"title\":\"Git Namespaces — Bridge Job — response payload\",\"type\":\"object\"},\"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.\",\"enum\":[\"git.ns.admin\",\"git.repo.create\",\"git.repo.own\",\"git.repo.maintain\",\"git.commit.sign\"],\"title\":\"Right\",\"type\":\"string\"},\"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 `..`.\",\"maxLength\":100,\"minLength\":1,\"pattern\":\"^[a-z0-9_-][a-z0-9._-]*$\",\"title\":\"Segment\",\"type\":\"string\"},\"StepName\":{\"description\":\"One step of a forge adapter's plan. Forge-neutral names: `create`, `workflow`, `keyring`, `variables`, `requiredCheck`, `roles`, `archive`. An adapter MAY add its own (`mergeStyle`, `runner`), which a VTC displays but need not understand.\",\"maxLength\":64,\"minLength\":1,\"pattern\":\"^[a-z][A-Za-z0-9]*$\",\"type\":\"string\"}},\"$id\":\"https://trusttasks.org/spec/git-ns/bridge/job/0.2\",\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"additionalProperties\":false,\"description\":\"The VTC asks its bridge to do one piece of forge work in a namespace. The job names what to do (`kind`) and carries the desired state, never forge credentials — the bridge holds those. Which optional members a job carries is fixed by its `kind` (see the specification's kind table); a bridge refuses a job that carries a member its kind does not use, or lacks one its kind requires.\",\"properties\":{\"desiredRoles\":{\"description\":\"The complete set of people who should hold a forge role on the target. The bridge converges to exactly this set among the roles it manages: it adds or changes roles to match and removes managed roles not listed. `projectRoles` and `createRepo` only.\",\"items\":{\"$ref\":\"#/$defs/DesiredRole\"},\"type\":\"array\",\"uniqueItems\":true},\"ext\":{\"$ref\":\"#/$defs/Ext\"},\"jobId\":{\"$ref\":\"#/$defs/JobId\",\"description\":\"The VTC's identifier for this job. The bridge reports on it with git-ns/bridge/result.\"},\"kind\":{\"description\":\"What to do. `projectRoles` — converge forge roles to `desiredRoles`, and remove whatever role each of `removeAccounts` holds on `repo`. `createRepo` — create `repo`, run the bootstrap plan, and project `desiredRoles`. `bootstrap` — run the bootstrap plan, or the listed `steps` of it, on an existing `repo`. `archive` — archive `repo`. `inspect` — compare the forge with the projection for `repo`, or for the whole namespace. `beginBind` — start the proof that the binding admin controls `target`. `beginAccountLink` — start linking `subject`'s account on this namespace's forge.\",\"enum\":[\"projectRoles\",\"createRepo\",\"bootstrap\",\"archive\",\"inspect\",\"beginBind\",\"beginAccountLink\"],\"type\":\"string\"},\"namespace\":{\"$ref\":\"#/$defs/NamespaceId\",\"description\":\"The namespace the job acts in. It also selects the bridge's forge credentials for it.\"},\"removeAccounts\":{\"description\":\"Accounts whose direct role on `repo` the bridge removes, whatever that role is — including a role the bridge does not manage and would otherwise only report as drift. Matched by `forge` and `id`; `login` is display only. No account listed here may also appear in `desiredRoles`. `projectRoles` with `repo` only.\",\"items\":{\"$ref\":\"#/$defs/ForgeAccount\"},\"minItems\":1,\"type\":\"array\",\"uniqueItems\":true},\"repo\":{\"$ref\":\"#/$defs/RepoResource\",\"description\":\"The repository. Required for `createRepo`, `bootstrap` and `archive`. For `projectRoles`, absent means the namespace-level roles (organisation owners), where only `git.ns.admin` is projected. For `inspect`, absent means a sweep of every repository in the namespace.\"},\"spec\":{\"$ref\":\"#/$defs/RepoSpec\",\"description\":\"How to create the repository. `createRepo` only.\"},\"steps\":{\"description\":\"Run only these steps of the adapter's bootstrap plan, in the plan's order. Absent: the whole plan. `bootstrap` only.\",\"items\":{\"$ref\":\"#/$defs/StepName\"},\"minItems\":1,\"type\":\"array\",\"uniqueItems\":true},\"subject\":{\"$ref\":\"#/$defs/Did\",\"description\":\"The member whose forge account is being linked. `beginAccountLink` only.\"},\"target\":{\"$ref\":\"#/$defs/BindTarget\",\"description\":\"`beginBind` only.\"}},\"required\":[\"jobId\",\"namespace\",\"kind\"],\"title\":\"Git Namespaces — Bridge Job — payload\",\"type\":\"object\"}\n",
);
}
impl crate::Payload for Response {
const TYPE_URI: &'static str = "https://trusttasks.org/spec/git-ns/bridge/job/0.2#response";
const IS_PROOF_REQUIRED: bool = true;
const IS_ISSUED_AT_REQUIRED: bool = true;
const IS_RECIPIENT_REQUIRED: bool = true;
const PAYLOAD_SCHEMA: Option<&'static str> = Some(
"{\"$defs\":{\"BindTarget\":{\"additionalProperties\":false,\"description\":\"The forge owner whose control the binding admin is to prove.\",\"properties\":{\"forge\":{\"$ref\":\"#/$defs/ForgeHost\"},\"owner\":{\"$ref\":\"#/$defs/Segment\"}},\"required\":[\"forge\",\"owner\"],\"title\":\"BindTarget\",\"type\":\"object\"},\"DesiredRole\":{\"additionalProperties\":false,\"properties\":{\"account\":{\"$ref\":\"#/$defs/ForgeAccount\",\"description\":\"The subject's linked account on this namespace's forge.\"},\"right\":{\"$ref\":\"#/$defs/Right\",\"description\":\"The subject's highest effective right on the target, which the forge adapter maps to one of its roles.\"},\"subject\":{\"$ref\":\"#/$defs/Did\"}},\"required\":[\"subject\",\"account\",\"right\"],\"type\":\"object\"},\"Did\":{\"description\":\"A DID, compared by exact string equality.\",\"maxLength\":2048,\"pattern\":\"^did:[a-z0-9]+:\\\\S+$\",\"title\":\"Did\",\"type\":\"string\"},\"Ext\":{\"additionalProperties\":true,\"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.\",\"minProperties\":1,\"propertyNames\":{\"pattern\":\"^[a-z][a-z0-9-]*(\\\\.[a-z0-9-]+)+$\"},\"title\":\"Ext\",\"type\":\"object\"},\"ForgeAccount\":{\"additionalProperties\":false,\"description\":\"A person's account on one forge. `id` is authoritative; `login` is for display only, because logins can be renamed and re-registered.\",\"properties\":{\"forge\":{\"$ref\":\"#/$defs/ForgeHost\"},\"id\":{\"$ref\":\"#/$defs/ForgeId\"},\"login\":{\"description\":\"The account's current login, as the forge reported it when last seen. Display only.\",\"maxLength\":100,\"minLength\":1,\"type\":\"string\"}},\"required\":[\"forge\",\"id\",\"login\"],\"title\":\"ForgeAccount\",\"type\":\"object\"},\"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.\",\"maxLength\":253,\"minLength\":3,\"pattern\":\"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$\",\"title\":\"ForgeHost\",\"type\":\"string\"},\"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.\",\"maxLength\":64,\"minLength\":1,\"title\":\"ForgeId\",\"type\":\"string\"},\"JobId\":{\"description\":\"The VTC's identifier for a job, unique across the VTC's jobs.\",\"maxLength\":128,\"minLength\":1,\"type\":\"string\"},\"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.\",\"maxLength\":128,\"minLength\":1,\"title\":\"NamespaceId\",\"type\":\"string\"},\"RepoResource\":{\"description\":\"A forge-qualified resource naming exactly one repository: `<forge-host>/<owner>/<repo>`, lowercase.\",\"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}$\",\"title\":\"RepoResource\",\"type\":\"string\"},\"RepoSpec\":{\"additionalProperties\":false,\"properties\":{\"description\":{\"maxLength\":350,\"type\":\"string\"},\"visibility\":{\"$ref\":\"#/$defs/RepoVisibility\"}},\"required\":[\"visibility\"],\"type\":\"object\"},\"RepoVisibility\":{\"description\":\"Repository visibility on the forge.\",\"enum\":[\"public\",\"private\"],\"title\":\"RepoVisibility\",\"type\":\"string\"},\"Response\":{\"$anchor\":\"response\",\"additionalProperties\":false,\"description\":\"Whether the bridge took the job.\",\"properties\":{\"accepted\":{\"description\":\"`true` — the job is durably queued, or was already queued or running under this `jobId`; a git-ns/bridge/result follows. `false` — the bridge already finished this `jobId`; it does not run it again, and sends its git-ns/bridge/result again.\",\"type\":\"boolean\"},\"ext\":{\"$ref\":\"#/$defs/Ext\"},\"jobId\":{\"$ref\":\"#/$defs/JobId\"},\"next\":{\"additionalProperties\":false,\"description\":\"For `beginBind` and `beginAccountLink` when `accepted` is `true`: where the VTC sends the person.\",\"properties\":{\"expiresAt\":{\"format\":\"date-time\",\"type\":\"string\"},\"url\":{\"format\":\"uri\",\"maxLength\":2048,\"pattern\":\"^https://\",\"type\":\"string\"},\"userCode\":{\"description\":\"The device-flow code, for a forge that uses one.\",\"maxLength\":64,\"minLength\":1,\"type\":\"string\"}},\"required\":[\"url\",\"expiresAt\"],\"type\":\"object\"}},\"required\":[\"jobId\",\"accepted\"],\"title\":\"Git Namespaces — Bridge Job — response payload\",\"type\":\"object\"},\"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.\",\"enum\":[\"git.ns.admin\",\"git.repo.create\",\"git.repo.own\",\"git.repo.maintain\",\"git.commit.sign\"],\"title\":\"Right\",\"type\":\"string\"},\"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 `..`.\",\"maxLength\":100,\"minLength\":1,\"pattern\":\"^[a-z0-9_-][a-z0-9._-]*$\",\"title\":\"Segment\",\"type\":\"string\"},\"StepName\":{\"description\":\"One step of a forge adapter's plan. Forge-neutral names: `create`, `workflow`, `keyring`, `variables`, `requiredCheck`, `roles`, `archive`. An adapter MAY add its own (`mergeStyle`, `runner`), which a VTC displays but need not understand.\",\"maxLength\":64,\"minLength\":1,\"pattern\":\"^[a-z][A-Za-z0-9]*$\",\"type\":\"string\"}},\"$ref\":\"#/$defs/Response\",\"$schema\":\"https://json-schema.org/draft/2020-12/schema\"}\n",
);
}
impl crate::RequestPayload for Payload {
type Response = Response;
}
/// The earlier `MAJOR.MINOR` of this slug that this version declares it
/// extends (front matter `extends`, SPEC §5.2 "Declared extension"), or
/// `None`. Only the direct declaration; walk a chain with
/// [`crate::extension::extends_for`].
pub const EXTENDS: Option<&str> = None;
/// 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::UNKNOWN_NAMESPACE,
error_codes::NOT_CAPABLE,
error_codes::JOB_ID_REUSED,
];
/// 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:unknownNamespace`
///
/// No namespace bound to this VTC has this identifier, or contains this resource.
///
/// Declared `retryable: false`.
pub const UNKNOWN_NAMESPACE: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "git-ns:unknownNamespace",
retryable: false,
details_schema: ::core::option::Option::None,
};
/// `git-ns/bridge/job:notCapable`
///
/// This forge, or this namespace on it, cannot perform this kind of job — for example `createRepo` on a personal account.
///
/// Declared `retryable: false`.
pub const NOT_CAPABLE: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "git-ns/bridge/job:notCapable",
retryable: false,
details_schema: ::core::option::Option::None,
};
/// `git-ns/bridge/job:jobIdReused`
///
/// The bridge already holds a job with this `jobId` and different content.
///
/// Declared `retryable: false`.
pub const JOB_ID_REUSED: crate::DeclaredErrorCode = crate::DeclaredErrorCode {
code: "git-ns/bridge/job:jobIdReused",
retryable: false,
details_schema: ::core::option::Option::None,
};
}