pub struct WireConfig {
pub upload: Config,
pub receive: Config,
pub lfs: Limits,
pub attest_objects: bool,
}Expand description
What gunnar-wire is configured with, for both directions.
gunnar-wire has had these knobs since it was written, and a
with_config on both state machines to receive them. Nothing ever called
either: this module said UploadPack::new(…) and ReceivePack::new(…), so
every deployment ran on Config::default() and an operator could not
decline filter — the one capability the type’s own doc comment says is
“the one capability an operator plausibly wants to decline”.
A configuration surface that cannot affect behaviour is worse than none.
It reads as a control that works: an appliance that had to state it does
not serve partial clones had Offered { filter: false } sitting right
there, fully implemented in both protocol versions, and no way at all to
reach it. So the knobs are wired rather than deleted, and this struct is
the one place the two gunnar_wire::…::Config types are held (one implementation) — a
second copy of agent or budget on ServeConfig is how a value ends up
honoured on one direction and stubbed on the other.
Fields§
§upload: ConfigWhat git-upload-pack serves under: offered, want_policy, budget
and limits.
receive: ConfigWhat git-receive-pack serves under: the connectivity budget.
lfs: LimitsWhat git-lfs-transfer serves under.
Held here and not beside the store for the same reason the two above
are: the LFS session is a third service on this one listener, and a
second home for its quota is how 8 GiB comes to be enforced by the SSH
path and not by the next caller. gunnar_lfs::Session::with_limits and
the three builders behind it had zero call sites outside
tests/quota.rs — every deployment ran on Limits::default() and the
numbers in the doc comments were not reachable from any command line.
attest_objects: boolEnumerate the objects each push introduced, so the push attestation can name them. On by default.
The ids are not a by-product of storing a pack — a pack entry does not
carry its oid — so answering this waits for the engine’s indexer to
drain, which is real latency on the push path
(storage::znippy_engine::ingest has the measured multiples). Before
this flag existed the enumeration happened only when a policy gate
needed it, and an attestation on a repository with no gates therefore
carried an empty object list that was indistinguishable from a push
that introduced nothing.
Turning it off does not restore that silence: the attestation then
records the reason the set is absent (new_object_oids_unknown), because an
absence that renders as a value is the defect this flag was added to
remove, not the behaviour it restores.
Implementations§
Source§impl WireConfig
impl WireConfig
Sourcepub fn from_serve_args(args: &ServeArgs) -> Result<Self>
pub fn from_serve_args(args: &ServeArgs) -> Result<Self>
The knobs an operator set on gunnar serve, translated once.
None on every flag means “the operator did not say”, which takes
gunnar-wire’s default — the same convention --max-concurrent-transfers
already uses. 0 is a stated value and is treated as one:
- on the two byte ceilings it is the documented way to remove them,
because
Limits’ fields areOptionandNonemeans unbounded; - on
--fetch-budgetit is refused, because the walk stops when it reaches the budget, so0would mean a server that answers no fetch at all while reading as “no limit”. An unbounded-looking flag that silently bricks the server is the failure this whole item is about.
Sourcepub fn lfs_session<'a>(
&self,
store: &'a dyn LfsStore,
operation: Operation,
) -> Session<'a>
pub fn lfs_session<'a>( &self, store: &'a dyn LfsStore, operation: Operation, ) -> Session<'a>
The one place an LFS session is built.
By construction rather than by a guard that watches two call sites
agree (one implementation). The defect this closes was exactly a second construction
path: Session::new(…).serve(…) in the SSH transport, with
with_limits reachable only from tests/quota.rs. A test that built
its own session could be green with the server on Limits::default()
forever, so the test drives this and there is nothing else to drive.
Trait Implementations§
Source§impl Clone for WireConfig
impl Clone for WireConfig
Source§impl Debug for WireConfig
impl Debug for WireConfig
Source§impl Default for WireConfig
impl Default for WireConfig
Source§fn default() -> Self
fn default() -> Self
Hand-written for one field. #[derive(Default)] would make
WireConfig::attest_objects false, and the safe default here is the
one that produces a complete attestation — the cheap default is the one
an operator opts into, never the one they get by forgetting.
Auto Trait Implementations§
impl !RefUnwindSafe for WireConfig
impl !UnwindSafe for WireConfig
impl Freeze for WireConfig
impl Send for WireConfig
impl Sync for WireConfig
impl Unpin for WireConfig
impl UnsafeUnpin for WireConfig
Blanket Implementations§
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request