Public Access
Let a host carry pinned folders, merged path by path
This commit is contained in:
@@ -17,9 +17,9 @@ public sealed class HostSecretCodecTests
|
||||
/// <remarks>
|
||||
/// "Full" cannot mean every field: the two authentication bindings are mutually exclusive, so a host may
|
||||
/// carry a key or a credential and never both, and neither may sit beside <c>AsksForPassword</c>. This
|
||||
/// one carries the credential, because that is the newer of the two, plus a group and a pair of tags —
|
||||
/// which are orthogonal to the binding and are what make this host reach the highest schema version a
|
||||
/// valid host can.
|
||||
/// one carries the credential, because that is the newer of the two, plus a group, a pair of tags and a
|
||||
/// pair of pinned paths — which are orthogonal to the binding and are what make this host reach the
|
||||
/// highest schema version a valid host can.
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public void AFullHost_RoundTrips()
|
||||
@@ -37,7 +37,8 @@ public sealed class HostSecretCodecTests
|
||||
relayEnabled: true,
|
||||
credentialId: credentialId,
|
||||
groupId: Production,
|
||||
tags: [Pci, EuWest]);
|
||||
tags: [Pci, EuWest],
|
||||
pinnedPaths: ["/var/www/app", "/var/log"]);
|
||||
|
||||
HostSecretCodec.TryDecode(HostSecretCodec.Encode(host), out var document).ShouldBeTrue();
|
||||
|
||||
@@ -219,6 +220,90 @@ public sealed class HostSecretCodecTests
|
||||
document.SchemaVersion.ShouldBe(HostSecretCodec.BaseSchemaVersion);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AHostPinningPaths_IsWrittenAtTheVersionThatIntroducedThem()
|
||||
{
|
||||
HostSecretCodec
|
||||
.TryDecode(HostSecretCodec.Encode(Host(pinnedPaths: ["/var/www/app"])), out var document)
|
||||
.ShouldBeTrue();
|
||||
|
||||
document.ShouldNotBeNull();
|
||||
document.SchemaVersion.ShouldBe(HostSecretCodec.PinnedPathsSchemaVersion);
|
||||
document.Host.PinnedPaths.ShouldBe(PinnedPathList.Create(["/var/www/app"]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AHostWithNoPinnedPaths_IsWrittenAtTheVersionItWouldHaveHadWithout()
|
||||
{
|
||||
// Pinning nothing is not using the feature, for the same reason an empty tag set is not: bumping
|
||||
// the version for it would have made every host in every vault read-only on every machine that had
|
||||
// not upgraded yet.
|
||||
HostSecretCodec.TryDecode(HostSecretCodec.Encode(Host(pinnedPaths: [])), out var document)
|
||||
.ShouldBeTrue();
|
||||
|
||||
document.ShouldNotBeNull();
|
||||
document.SchemaVersion.ShouldBe(HostSecretCodec.BaseSchemaVersion);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ATaggedHostThatAlsoPinsPaths_IsWrittenAtTheHigherOfTheTwoVersions()
|
||||
{
|
||||
// Independent fields, so the version is a maximum over both rather than whichever this switch
|
||||
// happened to check last — the same defect the group-and-binding case guards against above.
|
||||
HostSecretCodec
|
||||
.TryDecode(HostSecretCodec.Encode(Host(tags: [Pci], pinnedPaths: ["/var/www/app"])), out var document)
|
||||
.ShouldBeTrue();
|
||||
|
||||
document.ShouldNotBeNull();
|
||||
document.SchemaVersion.ShouldBe(HostSecretCodec.PinnedPathsSchemaVersion);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AHostPinningPaths_WritesThemLastAndInListOrder()
|
||||
{
|
||||
// Last, so every field that existed before them keeps its bytes; in list order rather than sorted,
|
||||
// unlike tags — order is the meaning of a pinned-path list, so canonicalising it away would lose
|
||||
// exactly what the feature is for.
|
||||
var bytes = HostSecretCodec.Encode(
|
||||
Host(username: null, notes: null, pinnedPaths: ["/var/www/app", "/var/log"]));
|
||||
|
||||
Encoding.UTF8.GetString(bytes).ShouldBe(
|
||||
"""
|
||||
{"schemaVersion":7,"label":"prod-db","hostname":"db.internal","port":22,"jumpHostIds":[],"options":{},"relayEnabled":false,"pinnedPaths":["/var/www/app","/var/log"]}
|
||||
""");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void APayloadWithoutPinnedPaths_DecodesAsPinningNothing()
|
||||
{
|
||||
// The compatibility case this field exists to pass: a payload written before pinned paths existed
|
||||
// must read cleanly as a host that pins nothing, not fail to decode.
|
||||
var payload = Encoding.UTF8.GetBytes(
|
||||
"""
|
||||
{"schemaVersion":6,"label":"prod-db","hostname":"db.internal","port":22,"tagIds":["0192f0c8-8888-7c3d-8e4f-5a6b7c8d9e08"]}
|
||||
""");
|
||||
|
||||
HostSecretCodec.TryDecode(payload, out var document).ShouldBeTrue();
|
||||
|
||||
document.ShouldNotBeNull().Host.PinnedPaths.ShouldBe(PinnedPathList.Empty);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void APayloadRepeatingAPinnedPath_DecodesKeepingTheFirstOccurrence()
|
||||
{
|
||||
// Written by some other client, and it must not compare unequal to the same list written once —
|
||||
// or the engine would push this host as changed on every pass for ever.
|
||||
var payload = Encoding.UTF8.GetBytes(
|
||||
"""
|
||||
{"schemaVersion":7,"label":"prod-db","hostname":"db.internal","port":22,"pinnedPaths":["/var/www/app","/var/log","/var/www/app"]}
|
||||
""");
|
||||
|
||||
HostSecretCodec.TryDecode(payload, out var document).ShouldBeTrue();
|
||||
|
||||
document.ShouldNotBeNull().Host.PinnedPaths
|
||||
.ShouldBe(PinnedPathList.Create(["/var/www/app", "/var/log"]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddingInheritanceAndTags_DidNotChangeTheBytesOfAHostUsingNeither()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user