Skip to content

keychain: Linux Filter returns ErrCredentialNotFound on empty/no-match while macOS & Windows return an empty map #579

Description

@tomyue-at-docker

Summary

The Linux Secret Service backend's Filter is the only platform that treats "no matching secrets" as an error (store.ErrCredentialNotFound). macOS and Windows return an empty (non-nil) map with a nil error for the same situation. This per-OS divergence in a shared interface method appears unnecessary and forces callers to special-case Linux.

Where

store/keychain/keychain_linux.go, Filter — empty collection:

if len(itemPaths) == 0 {
    return nil, store.ErrCredentialNotFound
}

...and again at the end of the same function when nothing matched the pattern:

if len(credentials) == 0 {
    return nil, store.ErrCredentialNotFound
}

Compare to keychain_darwin.go Filter, which returns make(map[store.ID]store.Secret) + nil even when empty (no empty-as-error guard). Windows behaves the same as macOS.

The Linux backend itself already acknowledges this asymmetry is undesirable — keychain_linux.go GetAllMetadata deliberately returns an empty map on an empty collection, with the comment:

An empty collection is a valid empty result for "list all", not a miss ... This matches the macOS and Windows backends, which have no empty-as-error guard.

Filter was apparently not given the same treatment.

Why it's a problem

  1. Semantics mismatch. Filter is a list/query operation. An empty result set is a normal, successful outcome — not a not-found condition. Get returning ErrCredentialNotFound makes sense; Filter doing so does not.
  2. Inconsistent interface contract. Callers coding against store.Store cannot rely on uniform behavior across backends, which defeats the purpose of the abstraction and makes bugs invisible to developers on macOS/Windows.

Expected behavior

Filter should return an empty, non-nil map[store.ID]store.Secret with a nil error when no secrets match, on all platforms — matching the existing behavior of GetAllMetadata and of the macOS/Windows Filter implementations.

Proposed fix

Remove both len(...) == 0 → ErrCredentialNotFound guards from keychain_linux.go Filter and return the (empty) credentials map instead. Update/relax any Linux Filter tests that assert ErrCredentialNotFound on empty.

Notes / risk

  • This is a behavior change for any Linux caller that currently relies on Filter returning ErrCredentialNotFound on empty. Such callers should already tolerate an empty map (that's what they get on macOS/Windows), but existing callers should be grepped for errors.Is(err, ErrCredentialNotFound) around Filter before shipping.
  • Consider documenting the empty-result contract explicitly on the Store.Filter interface method to prevent the three implementations from drifting again.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions