fix(tests): Fix Test4 broken JSON, Test2 false positive, add cleanup trap and Test9/Test10
This commit is contained in:
parent
4f583c9a03
commit
ad396fd6a2
2 changed files with 96 additions and 24 deletions
|
|
@ -49,6 +49,16 @@ namespace ServerMonitorManager.Desktop.Security.Tests
|
||||||
]
|
]
|
||||||
}";
|
}";
|
||||||
|
|
||||||
|
// Release JSON without the .sig asset — used by Test4
|
||||||
|
private const string NoSigReleaseJson = @"
|
||||||
|
{
|
||||||
|
""tag_name"": ""v0.1.0-alpha.9"",
|
||||||
|
""assets"": [
|
||||||
|
{ ""name"": ""server-monitor-manager-manifest.json"", ""browser_download_url"": ""https://example.com/releases/download/v0.1.0-alpha.9/server-monitor-manager-manifest.json"" },
|
||||||
|
{ ""name"": ""ServerMonitorManager-win-x64.msix"", ""browser_download_url"": ""https://example.com/releases/download/v0.1.0-alpha.9/ServerMonitorManager-win-x64.msix"" }
|
||||||
|
]
|
||||||
|
}";
|
||||||
|
|
||||||
private const string ValidManifestJson = @"
|
private const string ValidManifestJson = @"
|
||||||
{
|
{
|
||||||
""version"": ""v0.1.0-alpha.9"",
|
""version"": ""v0.1.0-alpha.9"",
|
||||||
|
|
@ -130,8 +140,7 @@ namespace ServerMonitorManager.Desktop.Security.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Test4_MissingSignature_Rejected()
|
public async Task Test4_MissingSignature_Rejected()
|
||||||
{
|
{
|
||||||
var noSigRelease = ValidReleaseJson.Replace("{ \"name\": \"server-monitor-manager-manifest.sig\"", "//");
|
var http = new MockHttpTransport { GetStringAsyncFunc = _ => Task.FromResult(NoSigReleaseJson) };
|
||||||
var http = new MockHttpTransport { GetStringAsyncFunc = _ => Task.FromResult(noSigRelease) };
|
|
||||||
var service = new UpdateService(http, new MockSignatureVerifier(), new MockFileStorage());
|
var service = new UpdateService(http, new MockSignatureVerifier(), new MockFileStorage());
|
||||||
|
|
||||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => service.CheckForUpdatesAsync());
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => service.CheckForUpdatesAsync());
|
||||||
|
|
@ -154,7 +163,7 @@ namespace ServerMonitorManager.Desktop.Security.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Test8_UpdateActionNotShownUntilVerified()
|
public async Task Test6_UpdateActionNotShownUntilVerified()
|
||||||
{
|
{
|
||||||
var http = new MockHttpTransport { GetStringAsyncFunc = url => Task.FromResult(url.EndsWith("releases/latest") ? ValidReleaseJson : ValidManifestJson) };
|
var http = new MockHttpTransport { GetStringAsyncFunc = url => Task.FromResult(url.EndsWith("releases/latest") ? ValidReleaseJson : ValidManifestJson) };
|
||||||
bool signatureVerified = false;
|
bool signatureVerified = false;
|
||||||
|
|
@ -173,7 +182,7 @@ namespace ServerMonitorManager.Desktop.Security.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Test9_PreReleaseChannel_Used()
|
public async Task Test7_PreReleaseChannel_Used()
|
||||||
{
|
{
|
||||||
var preReleaseJson = "[" + ValidReleaseJson.Replace("v0.1.0-alpha.9", "v0.1.0-alpha.10") + "]";
|
var preReleaseJson = "[" + ValidReleaseJson.Replace("v0.1.0-alpha.9", "v0.1.0-alpha.10") + "]";
|
||||||
var preReleaseManifest = ValidManifestJson.Replace("v0.1.0-alpha.9", "v0.1.0-alpha.10");
|
var preReleaseManifest = ValidManifestJson.Replace("v0.1.0-alpha.9", "v0.1.0-alpha.10");
|
||||||
|
|
@ -195,7 +204,7 @@ namespace ServerMonitorManager.Desktop.Security.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Test10_UrlAssetFromAnotherTag_Rejected()
|
public async Task Test8_UrlAssetFromAnotherTag_Rejected()
|
||||||
{
|
{
|
||||||
// Msix URL points to a different tag
|
// Msix URL points to a different tag
|
||||||
var maliciousRelease = ValidReleaseJson.Replace("v0.1.0-alpha.9/ServerMonitorManager-win-x64.msix", "v0.1.0-alpha.8/ServerMonitorManager-win-x64.msix");
|
var maliciousRelease = ValidReleaseJson.Replace("v0.1.0-alpha.9/ServerMonitorManager-win-x64.msix", "v0.1.0-alpha.8/ServerMonitorManager-win-x64.msix");
|
||||||
|
|
@ -206,5 +215,54 @@ namespace ServerMonitorManager.Desktop.Security.Tests
|
||||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => service.CheckForUpdatesAsync());
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => service.CheckForUpdatesAsync());
|
||||||
Assert.Contains("does not match the release tag", ex.Message);
|
Assert.Contains("does not match the release tag", ex.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Test9_ManifestVersionMismatch_Rejected()
|
||||||
|
{
|
||||||
|
// Manifest says v0.1.0-alpha.8 but release tag says v0.1.0-alpha.9
|
||||||
|
var mismatchedManifest = ValidManifestJson.Replace("v0.1.0-alpha.9", "v0.1.0-alpha.8");
|
||||||
|
var http = new MockHttpTransport
|
||||||
|
{
|
||||||
|
GetStringAsyncFunc = url =>
|
||||||
|
{
|
||||||
|
if (url.EndsWith("releases/latest")) return Task.FromResult(ValidReleaseJson);
|
||||||
|
if (url.EndsWith(".json")) return Task.FromResult(mismatchedManifest);
|
||||||
|
if (url.EndsWith(".sig")) return Task.FromResult("valid-sig");
|
||||||
|
return Task.FromResult("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var service = new UpdateService(http, new MockSignatureVerifier(), new MockFileStorage());
|
||||||
|
|
||||||
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => service.CheckForUpdatesAsync());
|
||||||
|
Assert.Contains("version", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Test10_MissingMsixAsset_Rejected()
|
||||||
|
{
|
||||||
|
// Release JSON without the MSIX asset
|
||||||
|
var noMsixRelease = @"
|
||||||
|
{
|
||||||
|
""tag_name"": ""v0.1.0-alpha.9"",
|
||||||
|
""assets"": [
|
||||||
|
{ ""name"": ""server-monitor-manager-manifest.json"", ""browser_download_url"": ""https://example.com/releases/download/v0.1.0-alpha.9/server-monitor-manager-manifest.json"" },
|
||||||
|
{ ""name"": ""server-monitor-manager-manifest.sig"", ""browser_download_url"": ""https://example.com/releases/download/v0.1.0-alpha.9/server-monitor-manager-manifest.sig"" }
|
||||||
|
]
|
||||||
|
}";
|
||||||
|
var http = new MockHttpTransport
|
||||||
|
{
|
||||||
|
GetStringAsyncFunc = url =>
|
||||||
|
{
|
||||||
|
if (url.EndsWith("releases/latest")) return Task.FromResult(noMsixRelease);
|
||||||
|
if (url.EndsWith(".json")) return Task.FromResult(ValidManifestJson);
|
||||||
|
if (url.EndsWith(".sig")) return Task.FromResult("valid-sig");
|
||||||
|
return Task.FromResult("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var service = new UpdateService(http, new MockSignatureVerifier(), new MockFileStorage());
|
||||||
|
|
||||||
|
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => service.CheckForUpdatesAsync());
|
||||||
|
Assert.Contains("MSIX", ex.Message, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
CLEANUP_FILES=()
|
||||||
|
cleanup() {
|
||||||
|
rm -f "${CLEANUP_FILES[@]}"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
echo "Running negative tests for manifest verification..."
|
echo "Running negative tests for manifest verification..."
|
||||||
|
|
||||||
if ! command -v cosign &> /dev/null; then
|
if ! command -v cosign &> /dev/null; then
|
||||||
|
|
@ -12,12 +18,15 @@ fi
|
||||||
export COSIGN_PASSWORD=""
|
export COSIGN_PASSWORD=""
|
||||||
cosign generate-key-pair
|
cosign generate-key-pair
|
||||||
export SMM_TEST_PUBKEY="cosign.pub"
|
export SMM_TEST_PUBKEY="cosign.pub"
|
||||||
|
CLEANUP_FILES+=(cosign.key cosign.pub)
|
||||||
|
|
||||||
ARCHIVE_NAME="test-archive.tar.gz"
|
ARCHIVE_NAME="test-archive.tar.gz"
|
||||||
echo "archive content" > "$ARCHIVE_NAME"
|
echo "archive content" > "$ARCHIVE_NAME"
|
||||||
ARCHIVE_HASH=$(sha256sum "$ARCHIVE_NAME" | awk '{print $1}')
|
ARCHIVE_HASH=$(sha256sum "$ARCHIVE_NAME" | awk '{print $1}')
|
||||||
|
CLEANUP_FILES+=("$ARCHIVE_NAME")
|
||||||
|
|
||||||
cat <<EOF > manifest.json
|
# Use the canonical manifest name that verify_archive() expects
|
||||||
|
cat <<EOF > server-monitor-manager-manifest.json
|
||||||
{
|
{
|
||||||
"hashes": {
|
"hashes": {
|
||||||
"$ARCHIVE_NAME": "$ARCHIVE_HASH"
|
"$ARCHIVE_NAME": "$ARCHIVE_HASH"
|
||||||
|
|
@ -25,10 +34,11 @@ cat <<EOF > manifest.json
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cosign sign-blob --yes --key cosign.key --output-signature manifest.sig manifest.json
|
cosign sign-blob --yes --key cosign.key --output-signature server-monitor-manager-manifest.sig server-monitor-manager-manifest.json
|
||||||
|
CLEANUP_FILES+=(server-monitor-manager-manifest.json server-monitor-manager-manifest.sig)
|
||||||
|
|
||||||
echo "Test 1: Valid signature and hash"
|
echo "Test 1: Valid signature and hash"
|
||||||
if ! bash deploy/ochenstarik-server-monitor-manager.sh verify-manifest manifest.json manifest.sig; then
|
if ! bash deploy/ochenstarik-server-monitor-manager.sh verify-manifest server-monitor-manager-manifest.json server-monitor-manager-manifest.sig; then
|
||||||
echo "FAIL: Valid payload rejected"
|
echo "FAIL: Valid payload rejected"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
@ -36,7 +46,8 @@ echo "PASS: Valid payload accepted"
|
||||||
|
|
||||||
echo "Test 2: Altered byte in archive"
|
echo "Test 2: Altered byte in archive"
|
||||||
echo "altered content" > "$ARCHIVE_NAME"
|
echo "altered content" > "$ARCHIVE_NAME"
|
||||||
# Note: we need to test archive verification for altered archive! The old test used verify-manifest which doesn't check archive.
|
# verify-release will call verify_archive → verify_manifest (signature check) then sha256 (hash check).
|
||||||
|
# The manifest was signed with the original hash, so the archive hash won't match.
|
||||||
if bash deploy/ochenstarik-server-monitor-manager.sh verify-release "$ARCHIVE_NAME" >/dev/null 2>&1; then
|
if bash deploy/ochenstarik-server-monitor-manager.sh verify-release "$ARCHIVE_NAME" >/dev/null 2>&1; then
|
||||||
echo "FAIL: Altered archive accepted"
|
echo "FAIL: Altered archive accepted"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
@ -46,39 +57,42 @@ echo "PASS: Altered archive rejected"
|
||||||
echo "Test 3: Substituted hash in manifest without resigning"
|
echo "Test 3: Substituted hash in manifest without resigning"
|
||||||
# Restore archive
|
# Restore archive
|
||||||
echo "archive content" > "$ARCHIVE_NAME"
|
echo "archive content" > "$ARCHIVE_NAME"
|
||||||
# Corrupt manifest
|
# Corrupt manifest (but don't re-sign — signature should now be invalid)
|
||||||
cat <<EOF > manifest.json
|
cat <<EOF > server-monitor-manager-manifest.json
|
||||||
{
|
{
|
||||||
"hashes": {
|
"hashes": {
|
||||||
"$ARCHIVE_NAME": "0000000000000000000000000000000000000000000000000000000000000000"
|
"$ARCHIVE_NAME": "0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
if bash deploy/ochenstarik-server-monitor-manager.sh verify-manifest manifest.json manifest.sig >/dev/null 2>&1; then
|
if bash deploy/ochenstarik-server-monitor-manager.sh verify-manifest server-monitor-manager-manifest.json server-monitor-manager-manifest.sig >/dev/null 2>&1; then
|
||||||
echo "FAIL: Substituted hash accepted"
|
echo "FAIL: Substituted hash accepted"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "PASS: Substituted hash rejected"
|
echo "PASS: Substituted hash rejected"
|
||||||
|
|
||||||
echo "Test 4: Manifest without signature"
|
echo "Test 4: Manifest without signature"
|
||||||
if bash deploy/ochenstarik-server-monitor-manager.sh verify-manifest manifest.json "" >/dev/null 2>&1; then
|
if bash deploy/ochenstarik-server-monitor-manager.sh verify-manifest server-monitor-manager-manifest.json "" >/dev/null 2>&1; then
|
||||||
echo "FAIL: Missing signature accepted"
|
echo "FAIL: Missing signature accepted"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "PASS: Missing signature rejected"
|
echo "PASS: Missing signature rejected"
|
||||||
|
|
||||||
echo "Test 5: Real alpha.8 manifest fallback matching"
|
echo "Test 5: Real alpha.8 manifest fallback matching (REQUIRES_NETWORK)"
|
||||||
ALPHA8_ARCHIVE="ochenstarik-server-monitor-manager-linux-x64.tar.gz"
|
ALPHA8_ARCHIVE="ochenstarik-server-monitor-manager-linux-x64.tar.gz"
|
||||||
wget -qO "$ALPHA8_ARCHIVE" https://github.com/ochenstarik-ui/server-monitor-manager/releases/download/v0.1.0-alpha.8/server-monitor-manager-linux-x64.tar.gz
|
if ! wget -qO "$ALPHA8_ARCHIVE" https://github.com/ochenstarik-ui/server-monitor-manager/releases/download/v0.1.0-alpha.8/server-monitor-manager-linux-x64.tar.gz; then
|
||||||
wget -qO server-monitor-manager-manifest.json https://github.com/ochenstarik-ui/server-monitor-manager/releases/download/v0.1.0-alpha.8/server-monitor-manager-manifest.json
|
echo "SKIP: Could not download alpha.8 archive (network unavailable)"
|
||||||
wget -qO server-monitor-manager-manifest.sig https://github.com/ochenstarik-ui/server-monitor-manager/releases/download/v0.1.0-alpha.8/server-monitor-manager-manifest.sig
|
else
|
||||||
unset SMM_TEST_PUBKEY
|
wget -qO server-monitor-manager-manifest.json https://github.com/ochenstarik-ui/server-monitor-manager/releases/download/v0.1.0-alpha.8/server-monitor-manager-manifest.json
|
||||||
if ! bash deploy/ochenstarik-server-monitor-manager.sh verify-release "$ALPHA8_ARCHIVE" >/dev/null 2>&1; then
|
wget -qO server-monitor-manager-manifest.sig https://github.com/ochenstarik-ui/server-monitor-manager/releases/download/v0.1.0-alpha.8/server-monitor-manager-manifest.sig
|
||||||
echo "FAIL: Alpha.8 real release verification failed"
|
CLEANUP_FILES+=("$ALPHA8_ARCHIVE")
|
||||||
exit 1
|
# Use keyless verification against real Sigstore/Rekor (requires network)
|
||||||
|
unset SMM_TEST_PUBKEY
|
||||||
|
if ! bash deploy/ochenstarik-server-monitor-manager.sh verify-release "$ALPHA8_ARCHIVE" >/dev/null 2>&1; then
|
||||||
|
echo "FAIL: Alpha.8 real release verification failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "PASS: Alpha.8 real release verification succeeded"
|
||||||
fi
|
fi
|
||||||
echo "PASS: Alpha.8 real release verification succeeded"
|
|
||||||
|
|
||||||
echo "All tests passed."
|
echo "All tests passed."
|
||||||
|
|
||||||
rm -f cosign.key cosign.pub manifest.json manifest.sig "$ARCHIVE_NAME" "$ALPHA8_ARCHIVE" server-monitor-manager-manifest.json server-monitor-manager-manifest.sig
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue