Skip to main content

SetupGap

Enum SetupGap 

Source
pub enum SetupGap {
    MissingKey(String),
    NotTrue {
        key: String,
        value: String,
    },
    CatchAllMissing,
    FilterUnresolved {
        paths: Vec<String>,
        total: usize,
        resolved: String,
    },
    CiphertextConverted {
        paths: Vec<String>,
        total: usize,
        culprit: String,
    },
    DeclarationMissing,
    SectionStale,
    Untracked(String),
}
Expand description

One reason git would not be filtering this repository.

Variants§

§

MissingKey(String)

A filter.git-xcrypt.* key is not set anywhere git reads.

§

NotTrue

The key is set, but not to anything git reads as true.

Fields

§key: String

The dotted key.

§value: String

What it is set to.

§

CatchAllMissing

.gitattributes carries no * filter=git-xcrypt line.

§

FilterUnresolved

Git resolves filter to something other than this tool for declared paths.

The catch-all is one line among many and git takes the last match, so an attribute line below the managed section, a .gitattributes in a subdirectory, or $GIT_DIR/info/attributes — which is not versioned and outranks everything — turns this tool off for paths it believes it protects. Measured on git 2.55: git check-attr filter then answers unset, the next git add stores the plaintext, and every other check in this command passes.

Until 2026-08-04 this was a note: the report named the files and the lines and left the reader to run git check-attr. That was the last route to a green report on a repository that does not encrypt, because a note does not fail a CI gate.

Fields

§paths: Vec<String>

The declared paths git would not filter, capped for the message.

§total: usize

How many there are altogether.

§resolved: String

What git resolves instead, spelled as git check-attr spells it.

§

CiphertextConverted

Git converts the line endings of declared paths itself.

The twin of SetupGap::FilterUnresolved, on the second attribute the managed section sets, and it costs more rather than less. The section writes -text on every encrypted path precisely so that git’s own CRLF conversion never touches the ciphertext; an attribute line that outranks it puts the conversion back.

Measured on git 2.55, with sync freshly run so nothing else in this command had anything to say: a 2 MB file under secrets/** text lost 34 CR bytes out of its ciphertext, git add exited 0, git commit exited 0, and the checkout failed the authentication tag and left no file at all. Nobody can decrypt what was committed — not the author, not with the key, not ever. status printed VERDICT: no findings. and exited 0.

A gap rather than a note for the reason the unresolved filter is one: both mean the declaration is not enforced, and a note does not fail a CI gate.

Fields

§paths: Vec<String>

The declared paths git would convert, capped for the message.

§total: usize

How many there are altogether.

§culprit: String

The attribute line that decides it, with the file and line it sits in.

§

DeclarationMissing

.git-xcrypt is not there, so nothing declares what to encrypt.

Filed as a gap rather than only as a question since 2026-08-05. It is not an exposure — the check-in path refuses on this state, so no git add stores anything in the clear over it — but it is precisely a configuration that enforces nothing, and the remedy is a file, not a rotated secret. It still puts the rest of the run in undetermined, because without the declaration neither the index nor history can be judged at all.

§

SectionStale

The managed .gitattributes section no longer matches .git-xcrypt.

A gap since 2026-08-06, and a note before that (open decision 11). What forced the change was not the severity but a contradiction: on one and the same stale section sync --check exited 1 and status exited 0 printing VERDICT: no findings. — two commands of one tool disagreeing about one state, so the answer a CI job got depended on which one it happened to run.

The argument for keeping it a note is recorded rather than erased, because it is true: it takes a foreign text attribute to make this cost anything, since our own magic starts with NUL and text=auto or core.autocrlf alone see binary and leave the ciphertext be. So this is the one gap in this list that is conditional. It was resolved the other way because the condition is invisible from here — the foreign attribute may arrive in a .gitattributes a subdirectory away, or in $GIT_DIR/info/attributes, which is not versioned — and because a declaration whose -text does not reach every declared path is, in the plain sense of what this command answers, not being enforced.

What it costs when the condition is met is measured, on git 2.55: a 2 MB file lost 34 CR bytes out of its ciphertext, git add exited 0, the commit succeeded, and the checkout failed the authentication tag and left no file at all. Nobody can decrypt that blob, ever.

Every rendering this build writes counts as current, so a repository that ran sync --global or sync --ignorecase is not sent to run the very command that produced its section.

§

Untracked(String)

A file the whole mechanism bootstraps from is not tracked.

.gitattributes is what makes git call the filter and .git-xcrypt is what the filter reads. Neither is any use to a clone unless it is committed, and init creates them without committing them — so a repository can look perfectly configured locally and publish nothing that enforces anything. The clone finds out; the machine that pushed does not.

Trait Implementations§

Source§

impl Clone for SetupGap

Source§

fn clone(&self) -> SetupGap

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for SetupGap

Source§

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

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

impl Display for SetupGap

Source§

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

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

impl Eq for SetupGap

Source§

impl PartialEq for SetupGap

Source§

fn eq(&self, other: &SetupGap) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for SetupGap

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

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

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.