using AcDream.App.Configuration; using AcDream.App.Credentials; namespace AcDream.App.Tests.Credentials; /// /// Campaign LA slice LA1: is a minimal /// port of AcDream.Headless.Credentials.HeadlessCredentialResolver /// scoped to the App session-config credential shape — see that file's own /// doc for why it is an independent port rather than a shared reference. /// Mirrors HeadlessCredentialResolverTests's coverage. /// public sealed class AppCredentialResolverTests { [Fact] public void EnvironmentSecretIsRedactedAndErasable() { const string variable = "ACDREAM_LA1_TEST_ENV_SECRET"; const string secretValue = "test-secret-value"; Environment.SetEnvironmentVariable(variable, secretValue); try { var resolver = new AppCredentialResolver( TextReader.Null, Environment.CurrentDirectory, isLinux: false); AppCredentialSecret secret = resolver.Resolve( "session", new SessionCredentialDescriptor { Provider = SessionCredentialProviderKind.Environment, Reference = variable, }); Assert.Equal(secretValue, secret.Reveal()); Assert.DoesNotContain(secretValue, secret.ToString()); secret.Dispose(); Assert.True(secret.IsDisposed); Assert.Throws(secret.Reveal); } finally { Environment.SetEnvironmentVariable(variable, null); } } [Fact] public void StandardInputConsumesOneSecretWithoutEchoingIt() { const string secretValue = "stdin-secret"; var resolver = new AppCredentialResolver( new StringReader(secretValue + Environment.NewLine), Environment.CurrentDirectory, isLinux: false); using AppCredentialSecret secret = resolver.Resolve( "session", new SessionCredentialDescriptor { Provider = SessionCredentialProviderKind.StandardInput, Reference = "session-stdin", }); Assert.Equal(secretValue, secret.Reveal()); Assert.DoesNotContain(secretValue, secret.ToString()); } [Fact] public void CredentialFileIsResolvedRelativeToConfiguredDirectory() { string directory = Path.Combine( Path.GetTempPath(), $"acdream-app-credentials-{Guid.NewGuid():N}"); Directory.CreateDirectory(directory); string path = Path.Combine(directory, "session.pass"); File.WriteAllText(path, "file-secret" + Environment.NewLine); try { var resolver = new AppCredentialResolver( TextReader.Null, directory, isLinux: false); using AppCredentialSecret secret = resolver.Resolve( "session", new SessionCredentialDescriptor { Provider = SessionCredentialProviderKind.File, Reference = "session.pass", }); Assert.Equal("file-secret", secret.Reveal()); } finally { File.Delete(path); Directory.Delete(directory); } } [Fact] public void MissingSecretErrorNeverContainsAnotherSecret() { const string variable = "ACDREAM_LA1_TEST_OTHER_SECRET"; const string unrelatedSecret = "must-not-leak"; Environment.SetEnvironmentVariable(variable, unrelatedSecret); try { var resolver = new AppCredentialResolver( new StringReader(string.Empty), Environment.CurrentDirectory, isLinux: false); AppCredentialException error = Assert.Throws(() => resolver.Resolve( "session", new SessionCredentialDescriptor { Provider = SessionCredentialProviderKind.Environment, Reference = "ACDREAM_LA1_TEST_DOES_NOT_EXIST", })); Assert.DoesNotContain(unrelatedSecret, error.ToString()); } finally { Environment.SetEnvironmentVariable(variable, null); } } [Fact] public void LinuxRejectsGroupOrOtherCredentialPermissions() { if (!OperatingSystem.IsLinux()) return; string path = Path.Combine( Path.GetTempPath(), $"acdream-app-credential-{Guid.NewGuid():N}"); File.WriteAllText(path, "linux-secret"); File.SetUnixFileMode( path, UnixFileMode.UserRead | UnixFileMode.GroupRead); try { var resolver = new AppCredentialResolver( TextReader.Null, Path.GetDirectoryName(path)!, isLinux: true); Assert.Throws(() => resolver.Resolve( "session", new SessionCredentialDescriptor { Provider = SessionCredentialProviderKind.File, Reference = Path.GetFileName(path), })); } finally { File.Delete(path); } } }