Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions .github/workflows/develop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,10 @@ jobs:
uses: github/codeql-action/init@v4
with:
languages: 'csharp'
- name: Setup .NET 6.0
- name: Setup .NET 11.0
uses: actions/setup-dotnet@v5
with:
dotnet-version: 6.0.x
- name: Setup .NET 7.0
uses: actions/setup-dotnet@v5
with:
dotnet-version: 7.0.x
- name: Setup .NET 8.0
uses: actions/setup-dotnet@v5
with:
dotnet-version: 8.0.x
global-json-file: global.json
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ jobs:
- name: Setup Pages
uses: actions/configure-pages@v6

- name: Setup .NET 8.0
- name: Setup .NET 11.0
uses: actions/setup-dotnet@v5
with:
dotnet-version: 8.x
global-json-file: global.json

- name: Setup docfx
run: dotnet tool update -g docfx
run: dotnet tool install -g docfx --allow-roll-forward

- name: Build documentation
run: docfx ./docfx/docfx.json
Expand Down
12 changes: 2 additions & 10 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Setup .NET 6.0
- name: Setup .NET 11.0
uses: actions/setup-dotnet@v5
with:
dotnet-version: 6.0.x
- name: Setup .NET 7.0
uses: actions/setup-dotnet@v5
with:
dotnet-version: 7.0.x
- name: Setup .NET 8.0
uses: actions/setup-dotnet@v5
with:
dotnet-version: 8.0.x
global-json-file: global.json
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2021-2023 Jean-Sebastien Carle
Copyright (c) 2021-2026 Jean-Sebastien Carle

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
8 changes: 4 additions & 4 deletions OnePassword.NET.Tests/AccountPreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,14 @@ public void GetAccounts()

var account = accounts.First();

Assert.Multiple((Action)delegate
using (Assert.EnterMultipleScope())
{
Assert.That(account.Id, Is.Not.Empty);
Assert.That(account.Url, Is.EqualTo($"https://{AccountAddress}"));
Assert.That(account.UserId, Is.Not.Empty);
Assert.That(account.Email, Is.EqualTo(AccountEmail));
Assert.That(account.Shorthand, Is.EqualTo(AccountAddress[..AccountAddress.IndexOf('.', StringComparison.Ordinal)]));
});
}
});
}

Expand All @@ -98,15 +98,15 @@ public void GetAccount()
{
var account = OnePassword.GetAccount();

Assert.Multiple((Action)delegate
using (Assert.EnterMultipleScope())
{
Assert.That(account.Id, Is.Not.Empty);
Assert.That(account.Name, Is.EqualTo(AccountName));
Assert.That(account.Domain, Is.EqualTo(AccountAddress[..AccountAddress.IndexOf('.', StringComparison.Ordinal)]));
Assert.That(account.Type, Is.Not.EqualTo(AccountType.Unknown));
Assert.That(account.State, Is.EqualTo(State.Active));
Assert.That(account.Created, Is.Not.EqualTo(default(DateTimeOffset)));
});
}
});
}

Expand Down
8 changes: 4 additions & 4 deletions OnePassword.NET.Tests/Common/TestsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class TestsBase
private static readonly CancellationTokenSource TestCancellationTokenSource = new();
private static readonly CancellationTokenSource TearDownCancellationTokenSource = new();
private static readonly Uri DownloadSource = GetDownloadSource();
private static readonly HttpClient CliDownloadClient = new();
private static readonly string ExecutableName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "op.exe" : "op";
private static bool _initialSetupDone;

Expand Down Expand Up @@ -55,8 +56,7 @@ public async Task Setup()
var zipFileName = Path.Combine(WorkingDirectory, Path.GetFileName(DownloadSource.LocalPath));
var extractFilename = Path.Combine(WorkingDirectory, ExecutableName);

using var httpClient = new HttpClient();
await using (var stream = await httpClient.GetStreamAsync(DownloadSource.OriginalString))
await using (var stream = await CliDownloadClient.GetStreamAsync(DownloadSource.OriginalString))
await using (var fileStream = new FileStream(zipFileName, FileMode.Create))
await stream.CopyToAsync(fileStream);

Expand Down Expand Up @@ -98,7 +98,7 @@ protected static void Run(RunType runType, Action action)
{
action();
}
catch (NUnit.Framework.IgnoreException)
catch (IgnoreException)
{
throw;
}
Expand Down Expand Up @@ -145,7 +145,7 @@ private static string GetEnv(string name, string value)

private static Uri GetDownloadSource()
{
const string version = "v2.32.1";
const string version = "v2.42.0";

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return new Uri($"https://cache.agilebits.com/dist/1P/op2/pkg/{version}/op_windows_amd64_{version}.zip");
Expand Down
2 changes: 1 addition & 1 deletion OnePassword.NET.Tests/OnePassword.NET.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net11.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
Expand Down
77 changes: 36 additions & 41 deletions OnePassword.NET.Tests/OnePasswordManagerCommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ public class OnePasswordManagerCommandTests
[Test]
public void VersionIsTrimmed()
{
using var fakeCli = new FakeCli(versionOutput: "2.32.1\r\n");
using var fakeCli = new FakeCli(versionOutput: "2.42.0\r\n");

var manager = fakeCli.CreateManager();

Assert.That(manager.Version, Is.EqualTo("2.32.1"));
Assert.That(manager.Version, Is.EqualTo("2.42.0"));
}

[Test]
Expand Down Expand Up @@ -101,7 +101,7 @@ public void SaveFileAttachmentContentUsesGeneratedReference()
{
manager.SaveFileAttachmentContent("file-id", "item-id", "vault-id", outputPath);

Assert.That(fakeCli.LastArguments, Does.StartWith("read op://vault-id/item-id/file-id?attr=content --no-newline --force --out-file "));
Assert.That(fakeCli.LastArguments, Does.Match("^read \"?op://vault-id/item-id/file-id\\?attr=content\"? --no-newline --force --out-file "));
Assert.That(fakeCli.LastArguments, Does.Contain(outputPath));
}
finally
Expand All @@ -119,12 +119,12 @@ public void MoveItemStringOverloadUsesResolvedVaultIds()

manager.MoveItem("item-id", "current-vault-id", "destination-vault-id");

Assert.Multiple((Action)delegate
using (Assert.EnterMultipleScope())
{
Assert.That(fakeCli.LastArguments, Does.StartWith("item move item-id --current-vault current-vault-id --destination-vault destination-vault-id"));
Assert.That(fakeCli.LastArguments, Does.Not.Contain("{currentVaultId}"));
Assert.That(fakeCli.LastArguments, Does.Not.Contain("{destinationVaultId}"));
});
}
}

[Test]
Expand All @@ -139,13 +139,13 @@ public void SearchForDocumentCreatesMissingOutputDirectory()
{
manager.SearchForDocument("document-id", outputFilePath, "vault-id");

Assert.Multiple((Action)delegate
using (Assert.EnterMultipleScope())
{
Assert.That(Directory.Exists(outputDirectory), Is.True);
Assert.That(fakeCli.LastArguments, Does.StartWith("document get document-id --out-file "));
Assert.That(fakeCli.LastArguments, Does.Contain(outputFilePath));
Assert.That(fakeCli.LastArguments, Does.Contain(" --force --vault vault-id"));
});
}
}
finally
{
Expand All @@ -163,7 +163,7 @@ public void GetSecretUsesTrimmedReference()

manager.GetSecret(" op://vault/item/field ");

Assert.That(fakeCli.LastArguments, Does.StartWith("read op://vault/item/field --no-newline"));
Assert.That(fakeCli.LastArguments, Does.Match("^read \"?op://vault/item/field\"? --no-newline"));
}

[Test]
Expand All @@ -177,7 +177,7 @@ public void SaveSecretUsesTrimmedReference()
{
manager.SaveSecret(" op://vault/item/field ", outputPath);

Assert.That(fakeCli.LastArguments, Does.StartWith("read op://vault/item/field --no-newline --force --out-file "));
Assert.That(fakeCli.LastArguments, Does.Match("^read \"?op://vault/item/field\"? --no-newline --force --out-file "));
Assert.That(fakeCli.LastArguments, Does.Contain(outputPath));
}
finally
Expand All @@ -196,22 +196,22 @@ public void RevokeGroupPermissionsUsesVaultGroupCommand()
manager.RevokeGroupPermissions("vault-id", "group-id", [VaultPermission.ViewItems]);

Assert.That(fakeCli.LastArguments, Does.StartWith("vault group revoke --vault vault-id --group group-id --permissions "));
Assert.That(fakeCli.LastArguments, Does.Contain("View Items"));
Assert.That(fakeCli.LastArguments, Does.Contain("view_items"));
}

[Test]
public void UpdateExtractsCurrentPlatformExecutablePayload()
{
using var fakeCli = new FakeCli(updateVersionOutput: "2.33.0\n");
using var fakeCli = new FakeCli(versionOutput: "2.41.1\n", updateVersionOutput: "2.42.0\n");
var manager = fakeCli.CreateManager();

var updated = manager.Update();

Assert.Multiple((Action)delegate
using (Assert.EnterMultipleScope())
{
Assert.That(updated, Is.True);
Assert.That(manager.Version, Is.EqualTo("2.33.0"));
});
Assert.That(manager.Version, Is.EqualTo("2.42.0"));
}
}

[Test]
Expand Down Expand Up @@ -263,7 +263,7 @@ public void CreateItemFailureKeepsTemplateDirty()

template.Title = "Updated Title";

Assert.Throws<InvalidOperationException>((Action)delegate
Assert.Throws<InvalidOperationException>(() =>
{
manager.CreateItem(template, "vault-id");
});
Expand All @@ -281,7 +281,7 @@ public void EditItemFailureKeepsItemDirty()

item.Title = "Updated Title";

Assert.Throws<InvalidOperationException>((Action)delegate
Assert.Throws<InvalidOperationException>(() =>
{
manager.EditItem(item, "vault-id");
});
Expand All @@ -303,13 +303,13 @@ public void EditItemPreservesCustomTemplateCategoryIdInPayload()
var root = jsonDocument.RootElement;
var fields = root.GetProperty("fields").EnumerateArray().ToList();

Assert.Multiple((Action)delegate
using (Assert.EnterMultipleScope())
{
Assert.That(root.GetProperty("category_id").GetString(), Is.EqualTo("custom-template-uuid"));
Assert.That(fields.Any(field =>
field.GetProperty("label").GetString() == "Environment"
&& field.GetProperty("value").GetString() == "Production"), Is.True);
});
}
}

[Test]
Expand All @@ -320,15 +320,15 @@ public void ShareItemWithoutEmailsOmitsEmailsFlag()

var result = manager.ShareItem("item-id", "vault-id");

Assert.Multiple((Action)delegate
using (Assert.EnterMultipleScope())
{
Assert.That(result.Url, Is.EqualTo(new Uri("https://share.example/item")));
Assert.That(result.ExpiresAt, Is.Null);
Assert.That(result.Recipients, Is.Empty);
Assert.That(result.ViewOnce, Is.Null);
Assert.That(fakeCli.LastArguments, Does.StartWith("item share item-id --vault vault-id"));
Assert.That(fakeCli.LastArguments, Does.Not.Contain("--emails"));
});
}
}

[Test]
Expand All @@ -339,12 +339,12 @@ public void ShareItemStringSingleEmailOverloadUsesEmailsFlag()

var result = manager.ShareItem("item-id", "vault-id", "recipient@example.com");

Assert.Multiple((Action)delegate
using (Assert.EnterMultipleScope())
{
Assert.That(result.Url, Is.Null);
Assert.That(result.Recipients, Is.Empty);
Assert.That(fakeCli.LastArguments, Does.Contain("--emails recipient@example.com"));
});
}
}

[Test]
Expand Down Expand Up @@ -433,48 +433,43 @@ public void ShareItemParsesStructuredShareResult()

var result = manager.ShareItem("item-id", "vault-id");

Assert.Multiple((Action)delegate
using (Assert.EnterMultipleScope())
{
Assert.That(result.Url, Is.EqualTo(new Uri("https://share.example/item")));
Assert.That(result.ExpiresAt, Is.EqualTo(DateTimeOffset.Parse("2026-03-15T12:00:00Z", CultureInfo.InvariantCulture)));
Assert.That(result.ViewOnce, Is.True);
Assert.That(result.Recipients, Is.EqualTo(ParsedRecipients));
});
}
}

private sealed class FakeCli : IDisposable
{
private readonly string _argumentsPath;
private readonly string _directoryPath;
private readonly string _errorOutputPath;
private readonly string _inputPath;
private readonly string _nextOutputPath;
private readonly string _updateMessagePath;
private readonly string _updatePayloadPath;
private readonly string _updatedVersionOutputPath;
private readonly string _versionOutputPath;

public FakeCli(string versionOutput = "2.32.1\n", string nextOutput = "{}", string? updateVersionOutput = null, string? errorOutput = null)
public FakeCli(string versionOutput = "2.42.0\n", string nextOutput = "{}", string? updateVersionOutput = null, string? errorOutput = null)
{
_directoryPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
_argumentsPath = Path.Combine(_directoryPath, "last-arguments.txt");
_errorOutputPath = Path.Combine(_directoryPath, "error-output.txt");
var errorOutputPath = Path.Combine(_directoryPath, "error-output.txt");
_inputPath = Path.Combine(_directoryPath, "last-input.txt");
_nextOutputPath = Path.Combine(_directoryPath, "next-output.txt");
_updateMessagePath = Path.Combine(_directoryPath, "update-output.txt");
var nextOutputPath = Path.Combine(_directoryPath, "next-output.txt");
var updateMessagePath = Path.Combine(_directoryPath, "update-output.txt");
_updatePayloadPath = Path.Combine(_directoryPath, "update-payload.zip");
_updatedVersionOutputPath = Path.Combine(_directoryPath, "updated-version-output.txt");
_versionOutputPath = Path.Combine(_directoryPath, "version-output.txt");
var updatedVersionOutputPath = Path.Combine(_directoryPath, "updated-version-output.txt");
var versionOutputPath = Path.Combine(_directoryPath, "version-output.txt");

Directory.CreateDirectory(_directoryPath);
File.WriteAllText(_nextOutputPath, nextOutput);
File.WriteAllText(_versionOutputPath, versionOutput);
File.WriteAllText(nextOutputPath, nextOutput);
File.WriteAllText(versionOutputPath, versionOutput);
if (errorOutput is not null)
File.WriteAllText(_errorOutputPath, errorOutput);
File.WriteAllText(errorOutputPath, errorOutput);
if (updateVersionOutput is not null)
{
File.WriteAllText(_updateMessagePath, $"Version {updateVersionOutput.Trim()} is now available.");
File.WriteAllText(_updatedVersionOutputPath, updateVersionOutput);
File.WriteAllText(updateMessagePath, $"Version {updateVersionOutput.Trim()} is now available.");
File.WriteAllText(updatedVersionOutputPath, updateVersionOutput);
CreateUpdatePayload();
}

Expand Down Expand Up @@ -633,7 +628,7 @@ private sealed class TestDocument(string id) : IDocument
public string Id { get; } = id;
}

private sealed class TestItem(string id) : OnePassword.Items.IItem
private sealed class TestItem(string id) : IItem
{
public string Id { get; } = id;
}
Expand Down
Loading
Loading