From a96afbb254675544a1f60cf7a6865b540785deac Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Tue, 15 Oct 2024 12:10:42 +0100 Subject: [PATCH] credstore: add no-op credential storage option Add a null/no-op credential store option that, as the name suggests, does nothing. This can be useful if the user wants to use another credential helper, configured in-front of GCM via Git, to store credentials. Example config: ```ini [credential] credentialStore = none helper = /bin/my-awesome-helper helper = /usr/local/bin/git-credential-manager ``` In this example, the `my-awesome-helper` will be consulted first to retrieve existing credentials before GCM, and will be asked to store any credentials generated by GCM. --- docs/configuration.md | 1 + docs/credstores.md | 26 ++++++++++++++++++++++++++ docs/environment.md | 1 + src/shared/Core/Constants.cs | 1 + src/shared/Core/CredentialStore.cs | 7 +++++++ src/shared/Core/NullCredentialStore.cs | 19 +++++++++++++++++++ 6 files changed, 55 insertions(+) create mode 100644 src/shared/Core/NullCredentialStore.cs diff --git a/docs/configuration.md b/docs/configuration.md index f843b839a..ba978ef30 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -585,6 +585,7 @@ _(unset)_|Windows: `wincredman`, macOS: `keychain`, Linux: _(none)_|- `gpg`|Use GPG to store encrypted files that are compatible with the [pass][pass] (requires GPG and `pass` to initialize the store).|macOS, Linux `cache`|Git's built-in [credential cache][credential-cache].|macOS, Linux `plaintext`|Store credentials in plaintext files (**UNSECURE**). Customize the plaintext store location with [`credential.plaintextStorePath`][credential-plaintextstorepath].|Windows, macOS, Linux +`none`|Do not store credentials via GCM.|Windows, macOS, Linux #### Example diff --git a/docs/credstores.md b/docs/credstores.md index 2964f5645..43811dc30 100644 --- a/docs/credstores.md +++ b/docs/credstores.md @@ -9,6 +9,7 @@ There are several options for storing credentials that GCM supports: - GPG/[`pass`][passwordstore] compatible files - Git's built-in [credential cache][credential-cache] - Plaintext files +- Passthrough/no-op (no credential store) The default credential stores on macOS and Windows are the macOS Keychain and the Windows Credential Manager, respectively. @@ -251,6 +252,31 @@ permissions on this directory such that no other users or applications can access files within. If possible, use a path that exists on an external volume that you take with you and use full-disk encryption. +## Passthrough/no-op (no credential store) + +**Available on:** _Windows, macOS, Linux_ + +**:warning: .** + +```batch +SET GCM_CREDENTIAL_STORE="none" +``` + +or + +```shell +git config --global credential.credentialStore none +``` + +This option disables the internal credential store. All operations to store or +retrieve credentials will do nothing, and will return success. This is useful if +you want to use a different credential store, chained in sequence via Git +configuration, and don't want GCM to store credentials. + +Note that you'll want to ensure that another credential helper is placed before +GCM in the `credential.helper` Git configuration or else you will be prompted to +enter your credentials every time you interact with a remote repository. + [access-windows-credential-manager]: https://support.microsoft.com/en-us/windows/accessing-credential-manager-1b5c916a-6a16-889f-8581-fc16e8165ac0 [aws-cloudshell]: https://aws.amazon.com/cloudshell/ [azure-cloudshell]: https://docs.microsoft.com/azure/cloud-shell/overview diff --git a/docs/environment.md b/docs/environment.md index 1973132ea..f321caa6c 100644 --- a/docs/environment.md +++ b/docs/environment.md @@ -716,6 +716,7 @@ _(unset)_|Windows: `wincredman`, macOS: `keychain`, Linux: _(none)_|- `gpg`|Use GPG to store encrypted files that are compatible with the [`pass` utility][passwordstore] (requires GPG and `pass` to initialize the store).|macOS, Linux `cache`|Git's built-in [credential cache][git-credential-cache].|Windows, macOS, Linux `plaintext`|Store credentials in plaintext files (**UNSECURE**). Customize the plaintext store location with [`GCM_PLAINTEXT_STORE_PATH`][gcm-plaintext-store-path].|Windows, macOS, Linux +`none`|Do not store credentials via GCM.|Windows, macOS, Linux #### Windows diff --git a/src/shared/Core/Constants.cs b/src/shared/Core/Constants.cs index 41ccb990c..191fcc83d 100644 --- a/src/shared/Core/Constants.cs +++ b/src/shared/Core/Constants.cs @@ -38,6 +38,7 @@ public static class CredentialStoreNames public const string SecretService = "secretservice"; public const string Plaintext = "plaintext"; public const string Cache = "cache"; + public const string None = "none"; } public static class RegexPatterns diff --git a/src/shared/Core/CredentialStore.cs b/src/shared/Core/CredentialStore.cs index 83f915d1e..11dc83818 100644 --- a/src/shared/Core/CredentialStore.cs +++ b/src/shared/Core/CredentialStore.cs @@ -100,6 +100,10 @@ private void EnsureBackingStore() _backingStore = new PlaintextCredentialStore(_context.FileSystem, plainStoreRoot, ns); break; + case StoreNames.None: + _backingStore = new NullCredentialStore(); + break; + default: var sb = new StringBuilder(); sb.AppendLine(string.IsNullOrWhiteSpace(credStoreName) @@ -168,6 +172,9 @@ private static void AppendAvailableStoreList(StringBuilder sb) sb.AppendFormat(" {1,-13} : store credentials in plain-text files (UNSECURE){0}", Environment.NewLine, StoreNames.Plaintext); + + sb.AppendFormat(" {1, -13} : disable internal credential storage{0}", + Environment.NewLine, StoreNames.None); } private void ValidateWindowsCredentialManager() diff --git a/src/shared/Core/NullCredentialStore.cs b/src/shared/Core/NullCredentialStore.cs new file mode 100644 index 000000000..fac92f47c --- /dev/null +++ b/src/shared/Core/NullCredentialStore.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; + +namespace GitCredentialManager; + +/// +/// Credential store that does nothing. This is useful when you want to disable internal credential storage +/// and only use another helper configured in Git to store credentials. +/// +public class NullCredentialStore : ICredentialStore +{ + public IList GetAccounts(string service) => Array.Empty(); + + public ICredential Get(string service, string account) => null; + + public void AddOrUpdate(string service, string account, string secret) { } + + public bool Remove(string service, string account) => false; +}