Skip to main content

ForgejoForge

Struct ForgejoForge 

Source
pub struct ForgejoForge { /* private fields */ }
Expand description

The Forgejo adapter: one bot user on one Forgejo (or Gitea) instance.

Holds the bot’s token (swappable, for rotation), the OAuth client secret, the webhook secret, and the namespaces the core has bound. Build it with ForgejoForge::connect, which probes the instance’s version and confirms the token is the bot’s.

Implementations§

Source§

impl ForgejoForge

Source

pub async fn connect( config: ForgejoConfig, credentials: Credentials, ) -> Result<Self>

Connect to config’s instance: probe /api/v1/version (switching off what the instance lacks), confirm credentials.bot_token belongs to config.bot_login, and — in the signing-key merge fallback on an instance without fast-forward-only merges — fetch the instance’s signing key for the plan.

Source

pub fn config(&self) -> &ForgejoConfig

The configuration.

Source

pub fn instance(&self) -> InstanceInfo

What the last probe found.

Source

pub fn bot(&self) -> ForgeAccount

The bot’s account.

Source

pub async fn refresh(&self) -> Result<InstanceInfo>

Probe the instance again (after an upgrade, say).

Source

pub fn register_namespace(&self, ns: Namespace) -> Result<()>

Tell the adapter about a bound namespace (from the VTC’s store). Operations on repositories in a namespace never registered are refused with ForgeError::NotBound.

Source

pub fn unregister_namespace(&self, ns: &Resource)

Forget a namespace (unbind).

Source

pub fn new_state() -> Result<String>

A fresh bind state nonce: 256 bits from the system CSPRNG, base64url. The caller stores it with its expiry and hands it back to Forge::complete_bind.

Source

pub async fn fetch_signing_key(&self) -> Result<Vec<u8>>

The instance’s merge-signing public key (/api/v1/signing-key.gpg).

Source

pub async fn replace_token(&self, new: Secret) -> Result<()>

Swap in a token an operator minted (manual rotation). It is checked to be the bot’s before it replaces the current one; the old token is not deleted — that is the operator’s to do.

Source

pub async fn mint_token(&self) -> Result<MintedToken>

Rotation, phase 1: mint a new bot token (basic auth with the bot’s password), verify it is the bot’s, and put it in use. Needs TokenRotation::WithPassword.

The new secret is returned: persist it (sealed) before calling ForgejoForge::retire_token, or a restart after the old token is deleted comes back with a dead credential. Nothing is deleted here — other bridge replicas using the old token keep working until the caller has distributed the new one and retires the old. The token it replaced is identified before anything is minted (by the id this adapter recorded when it minted it, or else by its last eight characters in the bot’s token list), so once the new token is in use nothing is left that can fail.

Source

pub async fn retire_token(&self, old: &TokenRef) -> Result<()>

Rotation, phase 2: delete a token this bridge replaced — exactly the one named, never a pattern, so another bridge’s (or a person’s) tokens on the same bot are never touched. Refuses the token in use. A token already gone is not an error.

Source

pub async fn refresh_managed_files( &self, repo: &Resource, files: &[ExtraFile], message: &str, ) -> Result<RefreshReport>

The Forgejo job for StepAction::RefreshProtectedFiles: the one sanctioned way the bridge changes a protected path (the managed workflow, the keyring) after bootstrap.

If every file already matches, nothing is touched. Otherwise the managed rule is opened for the bot alone — pushes enabled with a push allow-list of just the bot, the protected-file patterns cleared, since Forgejo refuses protected files even to an allowed pusher — the files are written, and the rule’s exact prior push and protected-file settings are restored and read back. The restore is attempted (twice) whatever happened to the writes. While open, an inspect reports the bot as a bypass actor and the paths as unprotected: critical drift, so a restore that failed is re-applied by the next sweep’s protection step.

Source

pub fn refresh_plan( &self, repo: &RepoSpec, cfg: &VgiConfig, ) -> Result<Vec<BootstrapStep>>

The single maintenance step that brings the managed workflow (and, in the signing-key fallback, the keyring) up to date on a bootstrapped repository — see ForgejoForge::refresh_managed_files.

Trait Implementations§

Source§

impl Debug for ForgejoForge

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Forge for ForgejoForge

Source§

fn diff(&self, observed: &RepoState, desired: &Projection) -> Vec<Drift>

The neutral comparison, with the check named as Forgejo reports it (<workflow> / <job> (pull_request)), plus what makes the check mean something on Forgejo: the protected workflow paths, fast-forward-only merges, and Actions being on.

Source§

fn kind(&self) -> ForgeKind

Which forge software this is.
Source§

fn host(&self) -> &str

The forge host this adapter serves (github.com, a GHES host, codeberg.org). Every resource it accepts starts with it; a resource on another host is refused rather than sent to the wrong forge.
Source§

fn capabilities(&self, ns: &Namespace) -> Capabilities

What this forge, and this namespace on it, can do. The core and the UX branch on this, never on Forge::kind.
Source§

fn begin_bind<'life0, 'async_trait>( &'life0 self, req: BindRequest, ) -> Pin<Box<dyn Future<Output = Result<BindStep>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Start binding a namespace: where to send the admin.
Source§

fn complete_bind<'life0, 'async_trait>( &'life0 self, cb: BindCallback, ) -> Pin<Box<dyn Future<Output = Result<NamespaceBinding>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Finish a bind from the forge’s callback. Validates the state nonce and that the credential landed on the expected owner.
Start linking a member’s forge account. member is their DID, for the adapter’s audit trail; nothing forge-side sees it.
Finish linking: the account’s numeric id and current login.
Source§

fn inspect<'life0, 'life1, 'async_trait>( &'life0 self, repo: &'life1 Resource, ) -> Pin<Box<dyn Future<Output = Result<RepoState>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Observe a repository’s current state.
Source§

fn create_repo<'life0, 'life1, 'async_trait>( &'life0 self, spec: &'life1 RepoSpec, ) -> Pin<Box<dyn Future<Output = Result<RepoState>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Create a repository. Refuses one that already exists with ForgeError::AlreadyExists — adopting it is a separate, elevated decision (§5.6), not something a retry should do silently.
Source§

fn archive_repo<'life0, 'life1, 'async_trait>( &'life0 self, repo: &'life1 Resource, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Archive a repository. Idempotent.
Source§

fn apply_roles<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, repo: &'life1 Resource, desired: &'life2 [RoleAssignment], unlisted: Unlisted, ) -> Pin<Box<dyn Future<Output = Result<ApplyReport>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Converge people’s direct roles on a repository to desired. Collaborators desired does not mention are handled per unlisted.
Source§

fn bootstrap_plan( &self, repo: &RepoSpec, cfg: &VgiConfig, ) -> Result<Vec<BootstrapStep>>

The steps that turn commit trust on for this forge’s CI.
Source§

fn run_step<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, repo: &'life1 Resource, step: &'life2 BootstrapStep, ) -> Pin<Box<dyn Future<Output = Result<StepOutcome>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Run one step, check-then-apply.
Source§

fn parse_event( &self, headers: &HeaderMap, body: &[u8], ) -> Result<Option<ForgeEvent>>

Verify and translate a webhook. Ok(None) for a verified delivery the core has no use for; Err for one that failed verification — which must not be acted on.
Source§

fn normalize(&self, raw: &str) -> Result<Resource, ForgeError>

Canonical form of a forge path. The default applies the owner[/repo] grammar GitHub and Forgejo share and refuses a resource on another host.
Source§

fn map_role( &self, ns: &Namespace, rights: EffectiveRights, map: &RoleMap, ) -> ForgeRole

Rights → this forge’s role for one person on one repository in ns. The default asks map for a role and rounds it down onto the namespace’s ladder.
Source§

impl ForgeHooks for ForgejoForge

Source§

fn before_apply_roles( &self, repo: &Resource, desired: &[RoleAssignment], ) -> HookDecision<Vec<RoleAssignment>>

The holder of a personal namespace owns every repository in it and cannot be added as a collaborator, so they are dropped from the desired set before it reaches Forgejo (and before the core reports their “missing” role as drift).

Source§

fn before_create(&self, _spec: &RepoSpec) -> HookDecision<RepoSpec>

Before a repository is created. Modify replaces the spec.
Source§

fn after_create(&self, _state: &RepoState) -> HookDecision<Vec<BootstrapStep>>

After a repository is created. Modify adds steps for the core to run before the bootstrap plan (Forgejo sets fast-forward-only merges here).
Source§

fn after_bootstrap( &self, _repo: &Resource, _outcomes: &[(String, StepOutcome)], ) -> HookDecision<Vec<BootstrapStep>>

After a bootstrap plan ran. Modify adds follow-up steps.
Source§

fn on_event(&self, _event: &ForgeEvent) -> HookDecision<ForgeEvent>

On a verified event. Modify replaces it; Abort drops it.
Source§

fn on_drift( &self, _repo: &Resource, _drift: &[Drift], ) -> HookDecision<Vec<Drift>>

On drift found for a repository. Modify replaces the list (to suppress a forge’s known false positives).

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more